Neo4j有一种方法可以在一个密码查询中创建可变数量的关系吗?

时间:2017-02-24 18:13:10

标签: neo4j cypher

我想创建N个节点,每个节点之间具有顺序关系。

将我的要求视为为用户创建工作流程。在UI端,它可以发送一个json对象数组,这些对象必须按顺序相互关联。例如:

{steps: [ {name: 'step 1'}, {name: 'step2'}, {name: 'step3'}] }

我想从上面的json中创建3个节点并按顺序链接

(step 1)-[:has_next_step]->(step 2)-[:has_next_step]->(step 3)

有快速的方法吗?请记住,我的示例有3个节点,但实际上我可能有5-15个步骤,因此密码查询必须能够处理此变量输入。请注意,我也可以控制输入,所以如果有一个更简单的json params变量,我也可以使用它。

2 个答案:

答案 0 :(得分:2)

您可以,您将面临的唯一问题是,在迭代步骤集合时,您将无法识别代表该集合之前的元素的节点。

因此,您可以在查询开头使用时间戳作为标识符:

WITH {steps: [ {name: 'step 1'}, {name: 'step2'}, {name: 'step3'}] } AS object
WITH object.steps AS steps, timestamp() AS identifier
UNWIND range(1, size(steps)-1) AS i
MERGE (s:Step {id: identifier + "_" + (i-1)}) SET s.name = (steps[i-1]).name
MERGE (s2:Step {id: identifier + "_" + (i)}) SET s2.name = (steps[i]).name
MERGE (s)-[:NEXT]->(s2)

说明:

我用UNWIND迭代步骤集合,为了识别代表已经迭代的步骤的每个节点,我使用虚拟标识符作为事务的时间戳+" _" +序列光标。

在大规模上,您最好使用自己的标识符(如客户端生成的uuid),并对其有一个索引/唯一约束。

enter image description here

更高级:

您有一个用户节点并想要附加步骤(上下文:用户之前没有连接任何步骤)

创建一个虚拟用户:

CREATE (u:User {login:"me"})

创建步骤列表并附加到用户

WITH {steps: [ {name: 'step 1'}, {name: 'step2'}, {name: 'step3'}] } AS object
WITH object.steps AS steps, timestamp() AS identifier
UNWIND range(1, size(steps)-1) AS i
MERGE (s:Step {id: identifier + "_" + (i-1)}) SET s.name = (steps[i-1]).name
MERGE (s2:Step {id: identifier + "_" + (i)}) SET s2.name = (steps[i]).name
MERGE (s)-[:NEXT]->(s2)
WITH identifier + "_" + (size(steps)-1) AS lastStepId, identifier + "_0" AS firstStepId
MATCH (user:User {login:"me"})
OPTIONAL MATCH (user)-[r:LAST_STEP]->(oldStep)
DELETE r
WITH firstStepId, lastStepId, oldStep, user
MATCH (s:Step {id: firstStepId})
MATCH (s2:Step {id: lastStepId})
MERGE (user)-[:LAST_STEP]->(s)
WITH s2, collect(oldStep) AS old
FOREACH (x IN old | MERGE (s2)-[:NEXT]->(x))

enter image description here

上下文,(运行相同的查询但使用不同的名称查看差异的步骤):用户已经附加了步骤:

WITH {steps: [ {name: 'second 1'}, {name: 'second 2'}, {name: 'second 3'}] } AS object
WITH object.steps AS steps, timestamp() AS identifier
UNWIND range(1, size(steps)-1) AS i
MERGE (s:Step {id: identifier + "_" + (i-1)}) SET s.name = (steps[i-1]).name
MERGE (s2:Step {id: identifier + "_" + (i)}) SET s2.name = (steps[i]).name
MERGE (s)-[:NEXT]->(s2)
WITH identifier + "_" + (size(steps)-1) AS lastStepId, identifier + "_0" AS firstStepId
MATCH (user:User {login:"me"})
OPTIONAL MATCH (user)-[r:LAST_STEP]->(oldStep)
DELETE r
WITH firstStepId, lastStepId, oldStep, user
MATCH (s:Step {id: firstStepId})
MATCH (s2:Step {id: lastStepId})
MERGE (user)-[:LAST_STEP]->(s)
WITH s2, collect(oldStep) AS old
FOREACH (x IN old | MERGE (s2)-[:NEXT]->(x))

enter image description here

答案 1 :(得分:2)

您可以使用几个APOC过程来创建节点,然后将它们链接在一起:

  • apoc.create.nodes可用于创建具有相同标签的多个节点。
  • apoc.nodes.link可用于将节点与相同类型的关系链接在一起。

例如,下面的查询将创建您的3个示例节点(带有Step标签),然后按顺序将它们链接在一起has_next_step关系:

CALL apoc.create.nodes(['Step'],[{name:'step1'},{name:'step2'},{name: 'step3'}]) YIELD node
WITH COLLECT(node) AS nodes
CALL apoc.nodes.link(nodes, 'has_next_step')
RETURN SIZE(nodes)

apoc.nodes.link过程不会返回任何内容,因此上述查询只返回已创建并链接在一起的节点数。