Merge
The MERGE
clause tries to match the query pattern in the database or, if not present, create the pattern in the database. MERGE <pattern>
can be interpreted as If MATCH <pattern> then RETURN <pattern> ELSE CREATE <pattern>
. Note that there is no notion of partially matching the pattern and creating the remaining parts. That is, either the whole pattern is matched or the whole pattern is created.
Similar to INSERT ON CONFLICT
in SQL, the MERGE
clause comes with ON CREATE
and ON MATCH
set operations, allowing you to specify additional update logic if the pattern is found or not found.
We will use the example database for demonstration, whose schema and data import commands are given here.
Merge Nodes
Merge existing nodes
The following query tries to merge a user with the name βAdamβ. Since βAdamβ exists in the database, no user is created.
MERGE (n:User {name : 'Adam'}) RETURN n.*;
ββββββββββ¬βββββββββ n.name β n.age ββ STRING β INT64 βββββββββββΌββββββββ€β Adam β 30 βββββββββββ΄ββββββββ
MATCH (:User) RETURN COUNT(*);
βββββββββββββββββ COUNT_STAR() ββ INT64 βββββββββββββββββ€β 4 βββββββββββββββββ
Merge non-existing nodes
The following query tries to merge a user with the name βBobβ. Since βBobβ does not exist in the database, a new user with the name βBobβ is created.
MERGE (n:User {name : 'Bob', age: 45}) RETURN n.*;
ββββββββββ¬βββββββββ n.name β n.age ββ STRING β INT64 βββββββββββΌββββββββ€β Bob β βββββββββββ΄ββββββββ
MATCH (:User) RETURN COUNT(*);
βββββββββββββββββ COUNT_STAR() ββ INT64 βββββββββββββββββ€β 5 βββββββββββββββββ
Merge with ON MATCH
ON MATCH
specifies the SET
operation once a match is found. The following query updates age property if pattern is matched.
MERGE (n:User {name : 'Adam'}) ON MATCH SET n.age = 35 RETURN n.*;
ββββββββββ¬βββββββββ n.name β n.age ββ STRING β INT64 βββββββββββΌββββββββ€β Adam β 35 βββββββββββ΄ββββββββ
Merge with ON CREATE
ON CREATE
specifies the SET
operation if no match is found. The following query updates age property if pattern is not matched.
MERGE (n:User {name : 'Bob'}) ON CREATE SET n.age = 60 RETURN n.*;
ββββββββββ¬βββββββββ n.name β n.age ββ STRING β INT64 βββββββββββΌββββββββ€β Bob β 60 βββββββββββ΄ββββββββ
Merge relationships
Merge existing relationships
The following query tries to merge a follows edge since 2020 between βAdamβ and βZhangβ. A match is found in this case.
MATCH (a:User), (b:User)WHERE a.name = 'Adam' AND b.name = 'Zhang'MERGE (a)-[e:Follows {since:2020}]->(b) RETURN e;
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ e ββ REL ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€β (0:0)-{_LABEL: Follows, _ID: 2:1, since: 2020}->(0:2) ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
MATCH (a:User)-[e:Follows]->(b:User)WHERE a.name = 'Adam' AND b.name = 'Zhang'RETURN e;
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ e ββ REL ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€β (0:0)-{_LABEL: Follows, _ID: 2:1, since: 2020}->(0:2) ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Merge non-existing relationships
The following query tries to merge a follows edge since 2022 between βAdamβ and βZhangβ. No match is found and an edge is created.
MATCH (a:User), (b:User)WHERE a.name = 'Adam' AND b.name = 'Zhang'MERGE (a)-[e:Follows {since:2022}]->(b) RETURN e;
---------------------------------------------------------| e |---------------------------------------------------------| (0:0)-{_LABEL: Follows, _ID: 0:4, since: 2022}->(0:2) |---------------------------------------------------------
MATCH (a:User)-[e:Follows]->(b:User)WHERE a.name = 'Adam' AND b.name = 'Zhang'RETURN e;
---------------------------------------------------------| e |---------------------------------------------------------| (0:0)-{_LABEL: Follows, _ID: 2:1, since: 2020}->(0:2) |---------------------------------------------------------| (0:0)-{_LABEL: Follows, _ID: 2:4, since: 2022}->(0:2) |---------------------------------------------------------
Merge with ON MATCH
Similar to merge nodes, the following query updates edge since property if the pattern is found.
MATCH (a:User), (b:User)WHERE a.name = 'Adam' AND b.name = 'Karissa'MERGE (a)-[e:Follows {since:2020}]->(b)ON MATCH SET e.since = 2021RETURN e;
---------------------------------------------------------| e |---------------------------------------------------------| (0:0)-{_LABEL: Follows, _ID: 2:0, since: 2021}->(0:1) |---------------------------------------------------------
Merge with ON CREATE
Similar to merge nodes, the following query updates edge since property if the pattern is not found.
MATCH (a:User), (b:User)WHERE a.name = 'Adam' AND b.name = 'Karissa'MERGE (a)-[e:Follows {since:2022}]->(b)ON CREATE SET e.since = 1999RETURN e;
---------------------------------------------------------| e |---------------------------------------------------------| (0:0)-{_LABEL: Follows, _ID: 0:5, since: 1999}->(0:1) |---------------------------------------------------------
Merge complex patterns
Previous examples have shown how to merge single node and relationship patterns. It is also possible to merge complex patterns involving multiple nodes and relationships.
MERGE (:User {name:'A'})-[:Follows]->(:User {name:'B'})-[:LivesIn]->(:City {name:'Toronto'});MATCH (a:User)-[:Follows]->(b:User)-[:LivesIn]->(c:City)RETURN a.name, b.name, c.name;
---------------------------------| a.name | b.name | c.name |---------------------------------| Adam | Karissa | Waterloo |---------------------------------| Karissa | Zhang | Kitchener |---------------------------------| Adam | Zhang | Kitchener |---------------------------------| Zhang | Noura | Guelph |---------------------------------| A | B | Toronto |---------------------------------