重绑定实体

  • 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)(此操作称为重新绑定/rebinding)。

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) 来重新绑定放置在映射(maps)、列表(lists)、路径(paths)或这三者组合中的多个实体。这将返回与传入参数相同的结构,但其中的实体已被重新绑定。例如

实体映射
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
© . This site is unofficial and not affiliated with Neo4j, Inc.