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)
来重新绑定放置在映射、列表、路径或这三者组合中的多个实体。这将返回与参数中传递的相同结构,但包含重新绑定的实体。例如
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
CREATE p1=(a:Foo)-[r1:MY_REL]->(b:Bar), p2=(:Bar)-[r2:ANOTHER_REL]->(c:Baz)
RETURN apoc.any.rebind([p1, p2]) as rebind