cancel
Showing results for 
Search instead for 
Did you mean: 

Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.

Multiple Relationships using multiple MERGE

Neo4j : 3.5.5
Driver: Python 1.7.2
Model is self explanatory. Book contains many instruments. Instrument has many dependencies

Query:
MERGE(book:Book {bookId:{bookId}})
MERGE (instr:Instrument {instrId:{instrId}, instrPath:{instrPath}})
MERGE (dep:Dependency {key:{pKey}, type:{pType}})
WITH book, instr, dep
MERGE (book)-[:CONTAINS]->(instr)-[:DEPENDENCIES]->(dep)
ON CREATE SET book.updated=datetime()
ON MATCH SET book.matched=datetime()

Novice to Cypher/Neo4J. I read in docs about MERGE, that multiple MERGE could be combined with MATCH/WITH.

Expectation: First three MERGE are supposed to create Nodes and last MERGE is supposed to Create Relationships using the previously created Nodes.

Output: Nodes are unique but Relationships are not.

Any pointers?

1 ACCEPTED SOLUTION

I had this issue too. The best way to Merge relationships without creating new ones is to do a collect(distinct (nodes)) before making relationships and only create a relationship if the new node is not already in that collection.

Something like

MERGE(book:Book {bookId:{bookId}})
MERGE (instr:Instrument {instrId:{instrId}, instrPath:{instrPath}})
MERGE (dep:Dependency {key:{pKey}, type:{pType}})
WITH book, instr, dep
OPTIONAL match (book)-[:CONTAINS]->(x) with book, instr,dep, collect(distinct x) as known_instr
OPTIONAL match (instr)-[:DEPENDENCIES]->(y) with book,instr,dep,known_instr,collect(distinct y) as known_dep
FOREACH (n in ( CASE WHEN NOT instr IN known_instr THEN [1] ELSE [] END ) |  CREATE (book)-[:CONTAINS]->(instr))
FOREACH (n in ( CASE WHEN NOT dep IN known_dep THEN [1] ELSE [] END ) |  CREATE (instr)-[:DEPENDENCIES]->(dep))
ON CREATE SET book.updated=datetime()
ON MATCH SET book.matched=datetime()

Something like that. What it is doing is getting a collection of nodes that are already related to the MERGE node. The reason MERGE relationship doesn't work like expected is because relationships don't have indexes for look ups.

Hope that helps.

View solution in original post

2 REPLIES 2

Try breaking up the pattern in your MERGE such that only one relationship is present in each:

...
MERGE (book)-[:CONTAINS]->(instr)
ON CREATE SET book.updated=datetime()
ON MATCH SET book.matched=datetime()
MERGE (instr)-[:DEPENDENCIES]->(dep)

You may want to read the article on understanding how MERGE works for more insight.

I had this issue too. The best way to Merge relationships without creating new ones is to do a collect(distinct (nodes)) before making relationships and only create a relationship if the new node is not already in that collection.

Something like

MERGE(book:Book {bookId:{bookId}})
MERGE (instr:Instrument {instrId:{instrId}, instrPath:{instrPath}})
MERGE (dep:Dependency {key:{pKey}, type:{pType}})
WITH book, instr, dep
OPTIONAL match (book)-[:CONTAINS]->(x) with book, instr,dep, collect(distinct x) as known_instr
OPTIONAL match (instr)-[:DEPENDENCIES]->(y) with book,instr,dep,known_instr,collect(distinct y) as known_dep
FOREACH (n in ( CASE WHEN NOT instr IN known_instr THEN [1] ELSE [] END ) |  CREATE (book)-[:CONTAINS]->(instr))
FOREACH (n in ( CASE WHEN NOT dep IN known_dep THEN [1] ELSE [] END ) |  CREATE (instr)-[:DEPENDENCIES]->(dep))
ON CREATE SET book.updated=datetime()
ON MATCH SET book.matched=datetime()

Something like that. What it is doing is getting a collection of nodes that are already related to the MERGE node. The reason MERGE relationship doesn't work like expected is because relationships don't have indexes for look ups.

Hope that helps.