Neo4j 用于将节点从一个列表结构移动到另一个列表结构的密码查询

Neo4j 用于将节点从一个列表结构移动到另一个列表结构的密码查询,neo4j,cypher,Neo4j,Cypher,我们有以下结构,其中用户是起点,带有数字的节点被标记为邀请,其值指定其属性id 我正在寻找一种方法来创建一个查询,将节点从有效的\u邀请关系指向的列表移动到无效的\u邀请指向的另一个列表。应在新列表中首先设置移动的节点 我提出了一个可行的解决方案,但由于缺乏Cypher方面的知识和经验,我恳请您和社区为其提供帮助和改进。 正如您将看到的,有很多命令式代码“hacks”(CASE-WHEN),而不是Cypher所认为的声明性代码。我将感谢所有的提示和建议 MATCH (u:User) MATCH

我们有以下结构,其中用户是起点,带有数字的节点被标记为邀请,其值指定其属性id

我正在寻找一种方法来创建一个查询,将节点从有效的\u邀请关系指向的列表移动到无效的\u邀请指向的另一个列表。应在新列表中首先设置移动的节点

我提出了一个可行的解决方案,但由于缺乏Cypher方面的知识和经验,我恳请您和社区为其提供帮助和改进。 正如您将看到的,有很多命令式代码“hacks”(CASE-WHEN),而不是Cypher所认为的声明性代码。我将感谢所有的提示和建议

MATCH (u:User)
MATCH (u)-[:VALID_INVITATIONS|PREVIOUS*]->(current:Invitation{ id:3 })

//find (current) node's predecessor which might pointing on it through VALID_INVITATIONS or PREVIOUS relationships
OPTIONAL MATCH (u)-[oldValidRel:VALID_INVITATIONS]->(current)
OPTIONAL MATCH (predecessor:Invitation)-[oldPredecessorRel:PREVIOUS]->(current)
//find (current) node's subsequent node
OPTIONAL MATCH (current)-[oldSubsequentRel:PREVIOUS]->(subsequent:Invitation)

//first we re-create connections in list pointed by VALID_INVITATION relationship for consistency
WITH *, CASE subsequent WHEN NULL THEN [] ELSE [1] END AS hasSubsequent

//if (current) node is connected to (u) User we replace VALID_INVITATIONS relationship
FOREACH(_ IN CASE oldValidRel WHEN NULL THEN [] ELSE [1] END |
    DELETE oldValidRel

    //if (subsequent) node exist then we need to re-link it
    FOREACH(_ IN hasSubsequent |
        MERGE (u)-[:VALID_INVITATIONS]->(subsequent)
        DELETE oldSubsequentRel
    )
)

//following condition should be XOR with the one above (only one must be executed)
//if (current) node has another Invitation node as predecessor in list
FOREACH(_ IN CASE oldPredecessorRel WHEN NULL THEN [] ELSE [1] END | 
    DELETE oldPredecessorRel

    //if (subsequent) node exist then we need to re-link it
    FOREACH(_ IN hasSubsequent |
        MERGE (predecessor)-[:PREVIOUS]->(subsequent)
        DELETE oldSubsequentRel
    )
)

WITH u, current

//now it is time to move (current) node to beginning of the list pointed by  INVALID_INVITATIONS relationship
MERGE (u)-[:INVALID_INVITATIONS]->(current)
WITH u, current
//find obsolete oldRel:INVALID_INVITATIONS relationship
MATCH (current)<-[:INVALID_INVITATIONS]-(u)-[oldRel:INVALID_INVITATIONS]->(oldInv)
DELETE oldRel
//link (current) with previously "first" node in INVALID_INVITATIONS list
MERGE (current)-[:PREVIOUS]->(oldInv)
匹配(u:用户)
匹配(u)-[:有效的邀请|以前的*]->(当前:邀请{id:3})
//查找(当前)节点的前置节点,该节点可能通过有效的\u邀请或以前的关系指向它
可选匹配(u)-[oldValidRel:有效邀请]->(当前)
可选匹配(前置:邀请)-[oldPredecessorRel:PREVIOUS]->(当前)
//查找(当前)节点的后续节点
可选匹配(当前)-[OldSubsequentRL:PREVIOUS]->(后续:邀请)
//首先,为了一致性,我们在有效的邀请关系所指向的列表中重新创建连接
带*,大小写为空,则[]ELSE[1]以hasSubsequent结尾
//如果(当前)节点连接到(u)用户,则替换有效的\u关系
FOREACH(u)如果oldValidRel为NULL,则[]否则[1]结束|
删除oldValidRel
//如果存在(后续)节点,则需要重新链接它
FOREACH(u)在hasSubsequent中|
合并(u)-[:有效的邀请]->(后续)
删除旧的子序列
)
)
//下面的条件应该和上面的条件异或(只有一个必须执行)
//如果(当前)节点在列表中有另一个邀请节点作为前置节点
FOREACH(如果oldPredecessorRel为空,则[]否则[1]结束)
删除旧的先人关系
//如果存在(后续)节点,则需要重新链接它
FOREACH(u)在hasSubsequent中|
合并(前置)-[:前置]->(后续)
删除旧的子序列
)
)
有u,电流
//现在是将(当前)节点移动到无效的\u关系所指向的列表的开头的时候了
合并(u)-[:无效的邀请]->(当前)
有u,电流
//查找过时的oldRel:无效的\u邀请关系
匹配(当前)(旧版本)
删除oldRel
//链接(当前)到无效邀请列表中以前的“第一个”节点
合并(当前)-[:上一个]->(旧版本)
在享受了一些“乐趣”和 我想出了一个更短的解决方案:

MATCH (u:User)-[:VALID_INVITATIONS|PREVIOUS*]->(current:Invitation {id:4})
MATCH (predecessor)-[oldPredecessorRel:VALID_INVITATIONS|PREVIOUS]->(current)
OPTIONAL MATCH (current)-[oldSubsequentRel:PREVIOUS]->(subsequent)

CALL apoc.do.when(subsequent IS NOT NULL, "CALL apoc.create.relationship($p, $r, NULL, $s) YIELD rel RETURN rel", "", {p:predecessor, r:type(oldPredecessorRel), s:subsequent}) YIELD value

DELETE oldPredecessorRel, oldSubsequentRel

WITH u, current
MERGE (u)-[:INVALID_INVITATIONS]->(current)
WITH u, current
MATCH (oldInv)<-[oldRel:INVALID_INVITATIONS]-(u)-[:INVALID_INVITATIONS]->(current)
DELETE oldRel
MERGE (current)-[:PREVIOUS]->(oldInv)
匹配(u:User)-[:有效的邀请|以前的*]->(当前:邀请{id:4})
匹配(前置)-[oldPredecessorRel:有效的邀请|先前]->(当前)
可选匹配(当前)-[oldSubsequentRel:PREVIOUS]->(后续)
调用apoc.do.when(contracted不为NULL),调用apoc.create.relationship($p,$r,NULL,$s)YIELD rel RETURN rel“,”,{p:preducer,r:type(oldPredecessorRel),s:contracted})YIELD value
删除oldPredecessorRel,oldSubsequentRel
有u,电流
合并(u)-[:无效的邀请]->(当前)
有u,电流
匹配(oldInv)(当前)
删除oldRel
合并(当前)-[:上一个]->(旧版本)

您是否考虑过使用一个链表,而不是两个链表(在它们之间移动东西非常复杂),其中每个节点都有一个'
isValid
属性?是的,我有,我决定不这样做,因为如果您只想找到一种类型的链表,为了匹配特定的类型,您必须遍历整个列表。一个列表是否可能比另一个长得多,最常见的用例是否会使用更长的列表?换句话说,使用一个列表真的会花费你很多吗?随着时间的推移,一个列表(无效的邀请)会越来越长,而有效的邀请会越来越短。无效邀请更像是在某个时间点“有效”的邀请的历史记录。即使有更好的解决方案,我也希望学习如何进行更好的查询,因此我想知道如何改进此解决方案。若涉及到设计部分,我会要求你们检查下面的帖子