Reputation: 404
Just learning about Graph Databases and NEO4J. I assume that the same distinction between compositional and aggregational relationships applies in Graph databases as in other databases.
Creating an aggregational relationship in NEO4J/Cypher, assuming we already have a Country node called 'Italy' in the database, the below query will create a Currency node called 'Euro' if one doesn't already exist and then create a relationship from Italy to Euro if that relationship doesn't already exist...
MATCH (co:Country {name:'Italy'})
MERGE (cu:Currency {name:'Euro'})
MERGE (co)-[cc:COUNTRYCURRENCY]->(cu)
RETURN cc
If there is not already a relationship Italy->Euro but there is already a Currency node 'Euro' (for example because we had already created the Euro for it to be used by another country, eg 'France'), then the above query would not create a second duplicate node called 'Euro'. it would reuse the existing 'Euro' node and create a new relationship to it from 'Italy'. This is correct behaviour for an aggregational relationship.
So say I want to merge a compositional relationship instead. IE If a parent already has a child with specified name/properties then I don't want to create a duplicate so I need to use MERGE. But if the specified parent doesn't have this child yet and there is already a child node for a different parent with the same name/properties as this child node then I want to create a new one in the context of this parent rather than reuse the existing one. So I need to make the whole operation conditional on whether a relationship already exists between the parent and a child having given properties. Is this syntactically possible in a one-liner?
Upvotes: 1
Views: 103
Reputation: 28756
In Neo4j any node is allowed to exist independently, there is no enforcement of a constraint that says the child can only exist while the parent does.
However you can:
Meanwhile a single relationship/edge can of course only exist between two nodes/vertices.
Question:
If I understood your question correctly:
Solution:
MERGE (p:Person {name: 'Jasper'})
MERGE (p)-[r:HAS_CHILD]-(c:Child {name: 'Kris'})
What happened:
Explanation:
Merge matches a whole pattern, so if that exact pattern does not exist, it will be treated as a create.
Upvotes: 1
Reputation: 30397
We have a knowledge base article on Understanding how MERGE works that covers several cases, including the one for this question.
The section in the article starting with "MERGE using combinations of bound and unbound variables for different use cases" covers what you're after. You want to MATCH or MERGE on the parent node, and then MERGE the relationship to the child node:
MERGE (p:Person {name: 'Jasper'})
MERGE (p)-[r:HAS_CHILD]->(c:Person {name: 'Kris'})
...
MERGE is like a MATCH, and if the MATCH fails, then a CREATE. When we already have bound variables (p is bound to a node because of the MERGE on the first line) then that existing bound node will be used, the node for p
won't be recreated.
Upvotes: 1