Neo4j有没有办法在一个密码查询中创建数量可变的关系?
我想创建N个节点,每个节点之间都有顺序关系 将我的需求视为为为用户创建工作流。在UI端,它可以发送json对象数组,这些对象必须按顺序相互关联。例如:Neo4j有没有办法在一个密码查询中创建数量可变的关系?,neo4j,cypher,Neo4j,Cypher,我想创建N个节点,每个节点之间都有顺序关系 将我的需求视为为为用户创建工作流。在UI端,它可以发送json对象数组,这些对象必须按顺序相互关联。例如: {steps:[{name:'step1'},{name:'step2'},{name:'step3'}]} 我希望从上面的json中创建3个节点,并将它们按顺序链接起来 (步骤1)-[:has_next_step]->(步骤2)-[:has_next_step]->(步骤3) 有没有快速的方法?请记住,我的示例有3个节点,但实际上我可能有5到1
{steps:[{name:'step1'},{name:'step2'},{name:'step3'}]}
我希望从上面的json中创建3个节点,并将它们按顺序链接起来
(步骤1)-[:has_next_step]->(步骤2)-[:has_next_step]->(步骤3)
有没有快速的方法?请记住,我的示例有3个节点,但实际上我可能有5到15个步骤,因此cypher查询必须能够处理这个变量输入。请注意,我也可以控制输入,因此如果有一个更简单的json params变量,我也可以使用它。可以,您将面临的唯一问题是,当迭代步骤集合时,您将无法识别表示集合中之前元素的节点 因此,稍加修改,您可以在查询的开头使用时间戳作为标识符:
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)并对其进行索引/唯一约束
更高级:
您有一个用户节点,希望将步骤附加到该节点(上下文:该用户以前没有任何步骤连接到该节点)
创建虚拟用户:
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))
上下文(运行相同的查询,但步骤名称不同,以直观地查看差异):用户已经附加了步骤:
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))
可以,您将面临的唯一问题是,在迭代步骤集合时,您将无法识别集合中之前表示元素的节点 因此,稍加修改,您可以在查询的开头使用时间戳作为标识符:
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)并对其进行索引/唯一约束
更高级:
您有一个用户节点,希望将步骤附加到该节点(上下文:该用户以前没有任何步骤连接到该节点)
创建虚拟用户:
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))
上下文(运行相同的查询,但步骤名称不同,以直观地查看差异):用户已经附加了步骤:
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))
您可以使用两个APOC过程来创建节点,然后将它们链接在一起:
可用于创建具有相同标签的多个节点apoc.create.nodes
可用于将节点与相同类型的关系链接在一起apoc.nodes.link
步骤
标签),然后使用下一步
关系将它们按顺序链接在一起:
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
过程不返回任何内容,因此上面的查询只返回创建并链接在一起的节点数。您可以使用两个apoc过程创建节点,然后将它们链接在一起:
可用于创建具有相同标签的多个节点apoc.create.nodes
可用于将节点与相同类型的关系链接在一起apoc.nodes.link
步骤
标签),然后使用下一步
关系将它们按顺序链接在一起:
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
过程不返回任何内容,因此上面的查询只返回创建并链接在一起的节点数。如果你有apoc,你可以使用apoc.nodes.link(nodes,“NEXT”)
我更喜欢人们在apoc:)之前学习密码,但是是的apoc FTW@Christophen Willemsen谢谢,我确实有一个uuid,但我只是举个例子。这很好用,当我更需要的时候,我会研究APOC。谢谢如果你有apoc,你可以使用apoc.nodes.link(nodes,“NEXT”)
我更喜欢人们在apoc:)之前学习密码,但是apoc FTW@Christophen Willemsen谢谢,我确实有一个uuid,但我只是举个例子。这很好用,当我更需要的时候,我会研究APOC。谢谢