Problem Statement
we want to match on property-id, if no match then match on property-name
- UPSERT on map.id ONLY IF map.id IS NOT NULL, otherwise
- UPSERT on map.name ONLY IF map.name IS NOT NULL
1 - OPTIONAL MATCH - Modify Node if Exists in DB, Otherwise Create Node
WITH {id: 9001, name:"Marcus Chiu", country:"USA", dob:date("1994-05-18")} AS map
OPTIONAL MATCH (n1:User {id: map.id}) -- USES INDEX
OPTIONAL MATCH (n2:User {name: map.name}) -- USES INDEX
WITH COALESCE(n1,n2) AS n, apoc.map.clean(map, [], []) AS map
FOREACH (ignoreMe IN CASE WHEN n IS NOT NULL THEN [1] ELSE [] END |
SET n += map, n.desc = "updated")
FOREACH (ignoreMe IN CASE WHEN n IS NULL THEN [1] ELSE [] END |
CREATE (n:User) SET n += map, n.desc = "created")
WITH {id: 9001, name:"Marcus Chiu", country:"USA", dob:date("1994-05-18")} AS map
OPTIONAL MATCH (n:User) WHERE (n.id = map.id) OR (n.name = map.name) -- INDEX NOT USED WHEN 'OR' ADDED INTO WHERE CLAUSE (tested in Neo4j v4.0.4)
WITH n, apoc.map.clean(map, [], []) AS map
FOREACH (ignoreMe IN CASE WHEN n IS NOT NULL THEN [1] ELSE [] END |
SET n += map, n.desc = "first")
FOREACH (ignoreMe IN CASE WHEN n IS NULL THEN [1] ELSE [] END |
CREATE (n:User) SET n += map, n.desc = "second")
2 - OPTIONAL MATCH - Modify Node if Exists in DB, Otherwise NO Create Node
WITH {id: 9001, name:"Marcus Chiu", country:"USA", dob:date("1994-05-18")} AS map
OPTIONAL MATCH (n1:User {id: map.id}) -- USES INDEX
OPTIONAL MATCH (n2:User {name: map.name}) -- USES INDEX
WITH COALESCE(n1,n2) AS n, apoc.map.clean(map, [], []) AS map
WHERE n IS NOT NULL SET n += map
RETURN n;
WITH {id: 9001, name:"Marcus Chiu", country:"USA", dob:date("1994-05-18")} AS map
OPTIONAL MATCH (n:User) WHERE (n.id = map.id) OR (n.name = map.name) -- INDEX NOT USED WHEN 'OR' ADDED INTO WHERE CLAUSE (tested in Neo4j v4.0.4)
WITH n, apoc.map.clean(map, [], []) AS map
WHERE n IS NOT NULL SET n += map
RETURN n;
3 - MERGE - Modify Node if Exists in DB, Otherwise Create Node
Behavior is slightly different than the 1 - OPTIONAL MATCH query above in this following edge-case:
- this MERGE query below will create a new node if map.id is non-null, whether or not the DB contains an existing node with a property name equal to map.name
- on the other hand, OPTIONAL MATCH query will update that existing node
WITH {id: 9001, name:"Marcus Chiu", country:"USA", dob:date("1994-05-18")} AS map
FOREACH (ignoreMe IN CASE WHEN NOT apoc.coll.contains(apoc.map.values(map, ["id"], true), null) THEN [1] ELSE [] END |
MERGE (u:User {id: map.id}) SET u += apoc.map.clean(map, [], []))
FOREACH (ignoreMe IN CASE WHEN apoc.coll.contains(apoc.map.values(map, ["id"], true), null) THEN [1] ELSE [] END |
FOREACH (ignoreMe IN CASE WHEN NOT apoc.coll.contains(apoc.map.values(map, ["name"], true), null) THEN [1] ELSE [] END |
MERGE (u:User {name: map.name}) SET u += apoc.map.clean(map, [], [])))