Cypher 'Node Already Exists' issue with MERGE - neo4j

I am preplexed on why I am getting an issue with this Cypher statment when I have a unique constraint on the address of the location node but am using a merge which should find that if it exists and only return the id for the rest of the statment. What am I missing?
Here is my statement:
MERGE(l:Location{location_name:"Starbucks", address:"36350 Van Dyke Ave", city: "Sterling Heights",state: "MI", zip_code:"48312",type:"location",room_number:"",long:-83.028889,lat:42.561152})
CREATE(m:Meetup{meet_date:1455984000,access:"Private",status:"Active",type:"project",did_happen:"",topic:"New features for StudyUup",agenda:"This is a brainstorming session to come with with new ideas for the companion website, StudyUup. Using MatchUup as the base, what should be added, removed, or modified? Bring your thinking caps and ideas!"})
WITH m,l
MATCH (g:Project{title_slug:"studyuup"}) MATCH (p:Person{username:"wkolcz"})
WITH m,l,g,p
MERGE (g)-[:CREATED {rating:0}]->(m)
MERGE (m)-[:MEETUP_AT {rating:0}]->(l)-[:HOSTED_MEETUP]->(m)
MERGE (m)<-[:ATTENDING]-(p)
RETURN id(m) as meeting_id
I am getting:
Node 416 already exists with label Location and property "address"=[36350 Van Dyke Ave]

You've encountered a common misunderstanding of MERGE. MERGE merges on everything you've specified within the single MERGE clause. So the order of operations are:
Search for a :Location node with all of the properties you've specified.
If found, return the node.
If not found, create the node.
Your problem occurs at step 3. Because a node with all of the properties you've specified does not exist, it goes to step 3 and tries to create a node with all of those properties. That's when your uniqueness constraint is violated.
The best practice is to merge on the property that you've constrained to be unique and then use SET to update the other properties. In your case:
MERGE (l:Location {address:"36350 Van Dyke Ave"})
SET l.location_name = "Starbucks",
l.city = "Sterling Heights"
...
The same logic is going to apply for the relationships you're merging later in the query. If the entire pattern doesn't exist, it's going to try to create the entire pattern. That's why you should stick to the best practice of:
MERGE (node1:Label1 {unique_property: "value"})
MERGE (node2:Label2 {unique_property: "value"})
MERGE (node1)-[:REL]-(node2)

Related

How to update a relation property in Neo4J Cypher?

I have the following Neo4J Cypher query:
MATCH (u:User {uid: $userId})
UNWIND $contextNames as contextName
MERGE (context:Context {name:contextName.name,by:u.uid,uid:contextName.uid})
ON CREATE SET context.timestamp=$timestamp
MERGE (context)-[:BY{timestamp:$timestamp}]->(u)
The last string always creates a new relation between the context and the u node. However, what if I just want to update it? How do I integrate this logic into the query above?
Do I have to add WITH context,u before the MERGE and then add rel:BY into the query?
Or do MATCH (context)-[rel:BY.... and then update the rel?
Just looking for the most efficient "best practices" way to do that.
Thanks!
There are two possible situation which might occur:
A relation between context and u is already present
A relation between context and u is not yet present (this will happen when contextwas just created by merge)
When you run the following line
MERGE (context)-[:BY{timestamp:$timestamp}]->(u)
Neo4j will check if there is already a relation BY in place between context and u with the given timestamp value. If yes, no new relation will be created. I guess that the timestamp is not a proper identifier for matching a relation, especially since you write that you want to update it. Therefore, I recommend to update the query in the following way:
MATCH (u:User {uid: $userId})
UNWIND $contextNames as contextName
MERGE (context:Context {name:contextName.name,by:u.uid,uid:contextName.uid})
ON CREATE SET context.timestamp=$timestamp
MERGE (context)-[by:BY]->(u)
SET by.timestamp=$timestamp
This way, a relation will be created if not already present. Either way, the timestamp will be set to the specified value.

How to let neo4j only checks if key duplication and not examine other attributes

For example, suppose a key is set
CREATE CONSTRAINT ON (n:Person) ASSERT (n.name) IS NODE KEY
Then if you execute the following code
MERGE (n1:Person{name:"John",data:13})
MERGE (n2:Person{name:"John",data:13}) // no error
MERGE (n3:Person{name:"John",data:14}) // key duplication error raised
MERGE (n4:Person{name:"Peter",data:15})
CREATE n3->[:pays]->n4 // want this line be executed with n3 being "John" added by the first line
a key duplication error will be raised for the third line, but not for the second line. This means internally neo4j engine checks if "data" is also duplicated. However, this might impact performance because my actual "data" attribute is a long text.
My question is:
Can I let neo4j only check key duplication and then give up creation if key exists without examining other attributes?
Also I don't want an error be raised, and need the fifth line be executed where n3 is the existing "John" added by the first line. Thanks!
For this case, I wouldn't worry about the comparison of your data property, especially if this is only comparison on a single node.
You can do an OPTIONAL MATCH instead of a MERGE, but this won't result in a creation attempt if no such node exists:
MERGE (n1:Person{name:"John", data:13})
OPTIONAL MATCH (n3:Person{name:"John", data:14})
MERGE (n4:Person{name:"Peter",data:15})
WITH n4, coalesce(n3, n1) as n3 // if n3 is null will use n1 instead
CREATE (n3)-[:pays]->(n4)
Alternately you can use MERGE with an ON CREATE to set the data property in case the MERGE resulted in node creation:
MERGE (n1:Person{name:"John", data:13})
MERGE (n3:Person{name:"John"})
ON CREATE SET n3.data = 14
MERGE (n4:Person{name:"Peter",data:15})
CREATE (n3)-[:pays]->(n4)
In the above, because you merged n3 by the name property, it will match on the same node as n1, and will not set the data property to 14 because the MERGE didn't result in node creation.
Just to note, you'll get similar behavior if you just have a unique constraint on :Person(name). The major difference between unique constraints and node keys is that node keys also include an inherent existence constraint on the property (the property must exist on all nodes of that label), and that multiple properties on the node can comprise a node key. Also, node key constraints (like existence constraints) are for enterprise edition only. For community edition, use unique constraints instead.

What is the difference between using/(not using) MATCH in a MERGE query in cypher?

When creating a probably existing node in neo4j, i'm getting confused about the use of MATCH. What would be the difference between these two cases?
1.-
MERGE (n:Person { user_id: 1234 ,sex:'male'})
2.- MATCH (a:Person) WHERE a.user_id = 1234 AND a.sex = 'male' MERGE (n:Person { user_id: 1234 ,sex:'male'})
Actually even after reading the documentation I can't understand the usefullness of MATCH
MERGE is "get or create". If the pattern exists, get it (bind to the variables specified). If the pattern specified does not exist, then create it.
MATCH is just "get". If the pattern exists, bind to the variables specified. If the pattern does not exist, then nothing is bound to the variables.
Here are the differences between your 2 queries.
Query #1 will create a node with the specified label and properties if and only if such a node is not found.
Query #2 is basically a waste of time. It calls MATCH to look for a node with the specified label and properties, and only if it is found does it call MERGE (which would create the node if and only if it does not already exist). So, #2 ends up never making any changes. If the node already existed, it will continue to exist (since MERGE will discover it doesn't need to do anything). If it did not exist, it will remain nonexistent (since MERGE would not even be invoked).
Needless to say, one would never want to use MATCH and MERGE in the same way as #2. Here is a more typical example of MATCH and MERGE, which ensures that the SPOUSE_OF relationship exists between 2 people who are already in the DB:
MATCH (a:Person {user_id: 1234}), (b:Person {user_id: 5678})
MERGE (a)-[:SPOUSE_OF]->(b);

Making a relation in neo4j

I am not sure what I am doing wrong here, so here is how I create nodes
CREATE (urlnode_1:UrlNode {url:'url1', nodenumber:1})
CREATE (urlnode_2:UrlNode {url:'url2', nodenumber:2})
I create relations as follows
CREATE
(urlnode_1)-[:OutLink {anchor_text:['MY']}]->(urlnode_2)
Two nodes are created successfully first, now on running the code to create the relation, I would have liked the relation to exist between the two created nodes but it creates two new nodes say 3 and 4 and shows a relation between them. What am i doing wrong here?
To guide you the best way I can, let's sum up some Neo4j basics concerning node and relationships creation :
A node can have one or more labels, labels are meaned to group the nodes by domain (User, Speaker, Company, etc..see a label as a table name for e.g. ). A node can also have properties.
A relationship can have only ONE type, relationships are organizing the graph. Relationships can also have properties.
To create a node, you can use the CREATE writing clause :
CREATE (n:Person {firstname: 'John'})
The CREATE statement will not check if other nodes with same label and properties already exists, it will just create a new node
Relationships can also be created with the same clause :
MATCH (n:Person {firstname: 'John'}), (p:Person {firstname: 'Pierre'})
CREATE (n)-[:KNOWS]->(p)
A complete pattern can also be created in one go :
CREATE (n:Person {name:'Chris'})-[:KNOWS]->(p:Person {name:'Oliver'})
REMINDER : CREATE will not check for existing nodes.
--- AND NOW MERGE ---
MERGE will lazily check for existing nodes, see him as a MATCH OR CREATE clause :
MERGE (n:Person {firstname:'Fred'})
If the node with label Person and firstname Fred does not exist, the node will be created, otherwise nothing will happen. This is where come the handy ON MATCH and ON CREATE mentionned by #joslinm .
If you run this query multiple times after the node creation, your graph will not change, if you know the http protocol, you can say that MERGE is an indempotent request.
Be aware that, MERGE will ensure that an entire pattern exist in the database, by creating it if it does not already exist, meaning that if you do MERGE with a complete pattern, the entire pattern will be looked up for existence, not a single node :
Say a node with label Person and name property with value 'John' already exist in the db :
MERGE (n:Person {name:'John'})
will not affect the graph
However :
MERGE (n:Person {name:'John'})-[:KNOWS]->(:Person {name:'Nathalia'})
A new John node will be created, because the entire pattern does not exist.
It is recommended to use MERGE incrementally :
MERGE (n:Person {name:'John'})
MERGE (p:Person {name:'Nathalia'})
MERGE (n)-[:KNOWS]->(p)
If you want to know more about the MERGE clause, I can highly recommend you this wonderful article from Luanne on GraphAware : http://graphaware.com/neo4j/2014/07/31/cypher-merge-explained.html
Chris
If you create a relationship, a new one will get created every single time. They are not inherently unique. It sounds like you'd rather be merging the relationship; i.e., if they relationship is there, match it, if not, create it.
The merge syntax for it is as follows:
MERGE (a:Node)-[:LIKES]->(b:Node)
ON
MATCH SET a.msg = 'I matched!'
ON
CREATE SET a.msg = 'I created!'
RETURN a
You can try it out here: http://console.neo4j.org/
You'll notice that first the msg will be "I created!" then after it matches, it will be "I matched!"

Neo4j Behaviour of Merge

So I have a use case where periodically I update my graph with complex subgraphs. In these subgraphs there will be nodes which are already in the graph, and nodes which are new. I had thought that Merge should do this, but in fact merge appears to create a new node even if there was already a unique node, if the property specifications are not identical.
E.g. on the Neo4j Console, Suppose that I do:
MERGE (a:Crew {name:'Neo', occupation:'The One'})
MERGE (a:Crew {name:'Adam', occupation:'Mechanic'})
CREATE UNIQUE (a)-[r:KNOWS]->(b)
RETURN *
That causes the console to create a second version of Neo, rather than to simple attach the occupation to the existing version.
This happens even if you use:
CREATE CONSTRAINT ON (p:Crew) ASSERT p.name IS UNIQUE
Although now it just refuses to create anything since it won't match the two neo's as one property is blank, and it isn't allowed to create a new node either.
It creates a second version because it's not unique. You're specifying an additional property, "occupation", which doesn't currently exist in the original Neo node, so it doesn't find a match and therefore creates a new node.
Use this instead:
MERGE (a:Crew {name:'Neo'}) ON CREATE SET a.occupation='The One'
MERGE (a:Crew {name:'Adam'}) ON CREATE SET b.occupation='Mechanic'
MERGE (a)-[r:KNOWS]->(b)
RETURN *
See also: http://docs.neo4j.org/refcard/2.1/

Resources