APOC 提供了一系列函数来重新绑定节点和关系

  • apoc.node.rebind(node)

  • apoc.rel.rebind(rel)

  • apoc.any.rebind(map/list/paths/…​)

为何使用这些函数

与 3.5 版本及之前不同,在 Neo4j 4+ 版本中,实体持有对其源事务的引用。

例如,当我们在一个事务中创建节点 n1,在新事务中创建节点 n2,然后通过 org.neo4j.graphdb.Node.createRelationshipTo()(即 n1.createRelationshipTo(n2))执行时,这可能会导致问题。

这是我们执行以下操作时发生的情况

// node creation
CREATE (:Article {content: 'contentBody'});

// iterate all (:Article) nodes and new transaction and rel creation
CALL apoc.periodic.iterate('MATCH (art:Article) RETURN art',
'CREATE (node:Category) with art, node call apoc.create.relationship(art, "CATEGORY", {b: 1}, node) yield rel return rel', {});

基本上,我们创建一个节点 (:Article),然后 apoc.periodic.iterate 的第二个参数打开一个新事务并创建一个节点 (:Category),最后我们尝试通过 apoc.create.relationship(它底层使用 org.neo4j.graphdb.Node.createRelationshipTo())在 (:Article)(:Category) 之间创建关系。

如果我们尝试执行第二个查询,apoc.periodic.iterate 将返回一个类似于以下的 errorMessage

Failed to invoke procedure `apoc.create.relationship`: Caused by: org.neo4j.graphdb.NotFoundException: Node[10] is deleted and cannot be used to create a relationship": 1

如何解决

为了解决之前的 apoc.periodic,iterate 问题,我们可以利用第一个语句返回的内部 ID,然后通过 ID 匹配节点,这意味着执行 MATCH (n) WHERE id(n) = id(nodeId)(此操作称为重新绑定)。

也就是说

CALL apoc.periodic.iterate('MATCH (art:Article) RETURN id(art) as id',
'CREATE (node:Category) WITH id, node MATCH (art) where id(art) = id
    WITH art, node call apoc.create.relationship(art, "CATEGORY", {b: 1}, node) yield rel return rel', {});

或者,我们可以使用 apoc.node.rebind 函数包装需要重新绑定的节点,如下所示:

CALL apoc.periodic.iterate('MATCH (art:Article) RETURN art',
'CREATE (node:Category) with art, node call apoc.create.relationship(art, "CATEGORY", {b: 1}, node) yield rel return rel', {});

对于关系,我们可以使用 apoc.rel.rebind

// other operations...
MATCH (:Start)-[rel:REL]->(:End) /*...*/ RETURN apoc.rel.rebind(rel)

我们还可以使用 apoc.any.rebind(ANY) 来重新绑定放置在 map、list、path 或这三者组合中的多个实体。这将返回与参数中传入的结构相同的结构,但实体已被重新绑定。例如:

实体 Map
CREATE (a:Foo)-[r1:MY_REL]->(b:Bar)-[r2:ANOTHER_REL]->(c:Baz) WITH a,b,c,r1,r2
RETURN apoc.any.rebind({first: a, second: b, third: c, rels: [r1, r2]}) as rebind
路径 List
CREATE p1=(a:Foo)-[r1:MY_REL]->(b:Bar), p2=(:Bar)-[r2:ANOTHER_REL]->(c:Baz)
RETURN apoc.any.rebind([p1, p2]) as rebind
© . All rights reserved.