Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.
05-14-2019 01:58 PM
Hello
When I use and re-use default mutation AddUserFriends, it is translated to CREATE and not MERGE, this way if I fire the same request again, I have always a new RELATION, what I really want is have just one UNIQUE relation, for example one :FRIENDS relation
for this I try to change the CREATE in generated query with MERGE
first I get the original non custom query from logs
MATCH (`user_from`:`User` {id: $from.id})
MATCH (`user_to`:`User` {id: $to.id})
CREATE (`user_from`)-[`friends_relation`:`FRIENDS`]->(`user_to`)
RETURN `friends_relation` { from: `user_from` { .name } ,to: `user_to` { .name } } AS `_AddUserFriendsPayload`;
I tested it in neo4j browser with :params
:params {"from": { id: "u3" },"to": { id: "u4" }}
and it work has expected
next I create a new custom mutation changing only the CREATE with MERGE, and create the type too for ex
type _AddUserFriendsPayload {
from: User
to: User
}
type Mutation {
AddUserFriends(from: _UserInput!, to: _UserInput!): _AddUserFriendsPayload @cypher(
statement:"""
MATCH (`user_from`:`User` {id: $from.id})
MATCH (`user_to`:`User` {id: $to.id})
MERGE (`user_from`)-[`friends_relation`:`FRIENDS`]->(`user_to`)
RETURN `friends_relation` { from: `user_from` { .name } ,to: `user_to` { .name } } AS `_AddUserFriendsPayload`;
""")
}
I compared the docs with and without custom mutation, and mutation and type are equal......
fire the mutation, the same mutation that works without custom mutation
mutation ($from: _UserInput!, $to: _UserInput!) {
AddUserFriends(from: $from, to: $to ) {
from {
name
}
to {
name
}
}
}
with query variables
{
"from": { "id": "u3" },
"to": { "id": "u4" }
}
I always have the result
{
"errors": [
{
"message": "Expected to find a node at ref slot 1 but found Map{from -> Map{name -> String(\"Jenny\")}, to -> Map{name -> String(\"Angie\")}} instead",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"AddUserFriends"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"code": "Neo.ClientError.Statement.TypeError",
"name": "Neo4jError",
"stacktrace": [
"Neo4jError: Expected to find a node at ref slot 1 but found Map{from -> Map{name -> String(\"Jenny\")}, to -> Map{name -> String(\"Angie\")}} instead",
"",
" at captureStacktrace (/media/mario/Storage/Development/Node/NodeGrandStackStarter/api/node_modules/neo4j-driver/lib/v1/result.js:200:15)",
" at new Result (/media/mario/Storage/Development/Node/NodeGrandStackStarter/api/node_modules/neo4j-driver/lib/v1/result.js:73:19)",
" at _newRunResult (/media/mario/Storage/Development/Node/NodeGrandStackStarter/api/node_modules/neo4j-driver/lib/v1/transaction.js:344:10)",
" at Object.run (/media/mario/Storage/Development/Node/NodeGrandStackStarter/api/node_modules/neo4j-driver/lib/v1/transaction.js:253:14)",
" at Transaction.run (/media/mario/Storage/Development/Node/NodeGrandStackStarter/api/node_modules/neo4j-driver/lib/v1/transaction.js:122:26)",
" at /media/mario/Storage/Development/Node/NodeGrandStackStarter/api/node_modules/neo4j-graphql-js/dist/index.js:71:25",
" at TransactionExecutor._safeExecuteTransactionWork (/media/mario/Storage/Development/Node/NodeGrandStackStarter/api/node_modules/neo4j-driver/lib/v1/internal/transaction-executor.js:136:22)",
" at TransactionExecutor._executeTransactionInsidePromise (/media/mario/Storage/Development/Node/NodeGrandStackStarter/api/node_modules/neo4j-driver/lib/v1/internal/transaction-executor.js:124:32)",
" at /media/mario/Storage/Development/Node/NodeGrandStackStarter/api/node_modules/neo4j-driver/lib/v1/internal/transaction-executor.js:67:15",
" at new Promise (<anonymous>)"
]
}
}
}
],
"data": {
"AddUserFriends": null
}
}
log result
CALL apoc.cypher.doIt("MATCH (`user_from`:`User` {id: $from.id})
MATCH (`user_to`:`User` {id: $to.id})
CREATE (`user_from`)-[`friends_relation`:`FRIENDS`]->(`user_to`)
RETURN `friends_relation` { from: `user_from` { .name } ,to: `user_to` { .name } } AS `_AddUserFriendsPayload`;", {from:$from, to:$to, first:$first, offset:$offset}) YIELD value
WITH apoc.map.values(value, [keys(value)[0]])[0] AS `_AddUserFriendsPayload`
RETURN `_AddUserFriendsPayload` {from: head([(`_AddUserFriendsPayload`)<-[`_AddUserFriendsPayload_from_relation`:`__ADD_USER_FRIENDS_PAYLOAD`]-(`_AddUserFriendsPayload_from`:`User`) | _AddUserFriendsPayload_from_relation { .name }]) ,to: head([(`_AddUserFriendsPayload`)-[`_AddUserFriendsPayload_to_relation`:`__ADD_USER_FRIENDS_PAYLOAD`]->(`_AddUserFriendsPayload_to`:`User`) | _AddUserFriendsPayload_to_relation { .name }]) } AS `_AddUserFriendsPayload`
{
"from": {
"id": "u3"
},
"to": {
"id": "u4"
},
"first": -1,
"offset": 0
}
if I copy the query in above log, and use it in neo4 it works
MATCH (`user_from`:`User` {id: $from.id})
MATCH (`user_to`:`User` {id: $to.id})
CREATE (`user_from`)-[`friends_relation`:`FRIENDS`]->(`user_to`)
RETURN `friends_relation` { from: `user_from` { .name } ,to: `user_to` { .name } } AS `_AddUserFriendsPayload`
returns
{
"from": {
"name": "Jenny"
},
"to": {
"name": "Angie"
}
}
after avoid some errors, I ended here, and I don't know what I require to create/replicate a custom mutation, just to learn how too use custom mutations and exchange CREATE with MERGE
another thing I think that make sense is use by default MERGE and not CREATE to this kind of stuff, this will prevent some duplication, but is just my humble opinion
maybe is a way to do it, and I don't know how.......
I read all the docs and topics in this channel but I can't find any help
UPDATE: the problem is relates with RETURN......but if I change RETURN to return the nodes with
RETURN `friends_relation` { from: `user_from`, to: `user_to` } AS `_AddUserFriendsPayload`;
the error message changes to
"message": "Expected to find a node at ref slot 1 but found Map{from -> (21), to -> (22)} instead"
where 21 and 22 are the id's......................it sems that info fields from payload are not passed to query ex { .name }....
thanks
ps: awsome work @William_Lyon and @michael.hunger ,
I really like your work and neo4j,
you really do a lot for neo4j community, thanks
05-26-2019 12:45 PM
it seems that nothing happens here...
time will tell, patience is virtue 🙂
UP. topic
08-16-2019 07:02 AM
Hi @marioammonteiro,
I was having a very similar problem. I wanted to MERGE
instead of CREATE
and my return was causing the error you describe: Expected to find a node at ref slot <some number> but found Map...
I'm still new to Neo4j/cypher/GraphQL, and I don't know if this is the ideal answer, but I was able to solve this by creating a completely new mutation, input, and payload for my query. For the input and return, the important part for me was to use a single object with no nested objects. I think this is because there was a lot of auto-generated types that weren't playing well together downstream.
You could try something like:
input CreateUserAndFriendInput {
userProp: String!
friendProp: String!
}
type CreateUserAndFriendPayload {
userProp: String
friendProp: String
}
type Mutation {
CreateUserAndFriend(input: CreateUserAndFriendInput!): CreateUserAndFriendPayload
@cypher(statement:"""
MERGE(user:User { userProp: input.userProp })-[:FRIENDS]->(friend:User { friendProp: input.friendProp })
RETURN { userProp: user.userProp, friendProp: friend.friendProp }
""")
}
Then be sure to exclude the CreateUserAndFriendPayload
from your auto-generated queries and mutations, as seen here
08-31-2019 06:12 AM
Thanks @dnllowe
I return to neo4j/graphql project yesterday
And only ser your answear right now
I will try it ASAP and leave ver the feedback
Once again thanks m8
03-27-2020 02:35 PM
after some time without time, I try it today and It work has expected just add exclude: ["AddUserFriends"]
to makeAugmentedSchema
const schema = makeAugmentedSchema({
typeDefs,
config: {
mutation: {
exclude: ["AddUserFriends"]
}
}
});
we can see in the logs the merge
CALL apoc.cypher.doIt("MATCH (`user_from`:`User` {id: $from.id})
MATCH (`user_to`:`User` {id: $to.id})
MERGE (`user_from`)-[`friends_relation`:`FRIENDS`]->(`user_to`)
RETURN user_from
// RETURN `friends_relation` { from: `user_from` , to: `user_to` } AS `_AddUserFriendsPayload`;", {from:$from, to:$to, first:$first, offset:$offset}) YIELD value
WITH apoc.map.values(value, [keys(value)[0]])[0] AS `user`
RETURN `user` { .id , .name ,friends: [(`user`)-[:`FRIENDS`]-(`user_friends`:`User`) | user_friends { .id , .name }] ,reviews: [(`user`)-[:`WROTE`]->(`user_reviews`:`Review`) | user_reviews { .id , .stars , .text }] ,avgStars: apoc.cypher.runFirstColumn("MATCH (this)-[:WROTE]->(r:Review) RETURN toFloat(avg(r.stars))", {this: user}, false)} AS `user`
{
"from": {
"id": "u3"
},
"to": {
"id": "u4"
},
"first": -1,
"offset": 0
}
thanks @dnllowe
All the sessions of the conference are now available online