Neo4j Cypher:仅当结束节点存在时才创建关系

Tez*_*zra 2 neo4j cypher

基于这个类似的问题,我想要最高效的方式来处理这种情况。

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))
Run Code Online (Sandbox Code Playgroud)

不幸的是,IF 不存在,并且 EXISTS 不能用于匹配或查找唯一节点。

  • 我不能使用 OPTIONAL MATCH,因为那样 CREATE UNIQUE 会抛出一个空异常(我希望它忽略空参数)
  • 我不能使用 MATCH,因为如果主题不存在,我将丢失所有行。
  • 我不能使用 MERGE,因为如果节点尚不存在,我不想创建它。
  • 我不能使用 APOC,因为我不能保证它可以在我们的 Neo4j 服务器上使用。

我现在最好的解决方案是

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
Run Code Online (Sandbox Code Playgroud)

然而,这看起来有点复杂,WITH本质上需要 2秒CREATE UNIQUE RELATION if start and end node exist(并且在计划中有一个渴望)。有没有可能做得更好?(使用 Cypher 3.1)

cyb*_*sam 5

你可以简化很多:

MERGE (a:TEST{id:1})
WITH a
MATCH (b:TEST{id:2})
CREATE UNIQUE (a)-[:HAS]->(b)
RETURN a;
Run Code Online (Sandbox Code Playgroud)

(单个)WITH子句用于将查询拆分为 2 个“子查询”。

因此,如果MATCH子查询失败,它只会中止自己的子查询(以及任何后续的子查询),但不会回滚之前成功的MERGE子查询。

但是请注意,无论何时最终子查询失败,该RETURN子句都不会返回任何内容。您必须确定这是否可以接受。

因为上面的RETURN子句只会在b存在时返回一些东西,所以它可能更有意义 returnb或路径。这是后者的示例(p即使路径已经存在,也会被分配一个值):

MERGE (a:TEST{id:1})
WITH a
MATCH (b:TEST{id:2})
CREATE UNIQUE p=(a)-[:HAS]->(b)
RETURN p;
Run Code Online (Sandbox Code Playgroud)

[更新]

在 Neo4j 4.0+ 中,CREATE UNIQUE不再支持,因此MERGE需要使用。

另外,如果你想返回a即使b不存在,你可以使用APOC功能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;
Run Code Online (Sandbox Code Playgroud)