Reputation: 8833
Building on this similar question, I want the most performant way to handle this scenario.
MERGE (n1{id:<uuid>})
SET n1.topicID = <unique_name1>
IF (EXISTS((a:Topic{id:<unique_name1>})) | CREATE UNIQUE (n1)-[:HAS]->(a))
MERGE (n2{id:<uuid>})
SET n2.topicID = <unique_name2>
IF (EXISTS((a:Topic{id:<unique_name2>})) | CREATE UNIQUE (n2)-[:HAS]->(a))
Unfortunately, IF doesn't exist, and EXISTS can't be used to match or find a unique node.
The best solution I have right now is
MERGE (a:TEST{id:1})
WITH a
OPTIONAL MATCH (b:TEST{id:2})
// collect b so that there are no nulls, and rows aren't lost when no match
WITH a, collect(b) AS c
FOREACH(n IN c | CREATE UNIQUE (a)-[:HAS]->(n))
RETURN a
However, this seems kinda complicated and needs 2 WITH
s for what is essentially CREATE UNIQUE RELATION if start and end node exist
(and in the plan there is an eager). Is it possible to do any better? (Using Cypher 3.1)
Upvotes: 3
Views: 4343
Reputation: 67044
You can simplify a quite a bit:
MERGE (a:TEST{id:1})
WITH a
MATCH (b:TEST{id:2})
CREATE UNIQUE (a)-[:HAS]->(b)
RETURN a;
The (single) WITH
clause serves to split the query into 2 "sub-queries".
So, if the MATCH
sub-query fails, it only aborts its own sub-query (and any subsequent ones) but does not roll back the previous successful MERGE
sub-query.
Note, however, that whenever a final sub-query fails, the RETURN
clause would return nothing. You will have to determine if this is acceptable.
Because the above RETURN
clause would only return something if b
exists, it might make more sense for it to return b
, or the path. Here is an example of the latter (p
will be assigned a value even if the path already existed):
MERGE (a:TEST{id:1})
WITH a
MATCH (b:TEST{id:2})
CREATE UNIQUE p=(a)-[:HAS]->(b)
RETURN p;
[UPDATE]
In neo4j 4.0+, CREATE UNIQUE
is no longer supported, so MERGE
needs to be used instead.
Also, if you want to return a
even if b
does not exist, you can use the APOC function apoc.do.when:
MERGE (a:TEST{id:1})
WITH a
OPTIONAL MATCH (b:TEST{id:2})
CALL apoc.do.when(
b IS NOT NULL,
'MERGE (a)-[:HAS]->(b)',
'',
{a: a, b: b}) YIELD value
RETURN a;
Upvotes: 7