Cypher Linked LIst: how to unshift and replace by index

后端 未结 2 1178
温柔的废话
温柔的废话 2021-01-26 07:22

I am trying to create a Linked List structure with Neo/Cypher as per the recomendation here: CYPHER store order of node relationships of the same label when I create

<         


        
相关标签:
2条回答
  • 2021-01-26 07:49

    [UPDATED]

    In the following queries, for simplicity I pretend that:

    • We find the Parent node of interest by name.
    • The relationship type of current interest is Foo.

    General Notes:

    • The OPTIONAL MATCH clauses find the sibling, if any, that should follow the child being inserted.
    • The FOREACH clauses take care of linking the that sibling, if any, to the child being inserted, and then deletes the obsolete relationship to that sibling.


    1. To unshift the Child having an id of 123 right after the Parent node:

      MATCH (p:Parent {name:"Fred"})
      OPTIONAL MATCH (p)-[r:Foo]->(c:Child)
      WITH p, r, COLLECT(c) AS cs
      MERGE (cNew:Child {id:123})
      CREATE (p)-[rNew:Foo]->(cNew)
      FOREACH (x IN cs | 
        CREATE (cNew)-[:Foo]->(x)
        DELETE r)
      RETURN p, rNew, cNew;
      
    2. To insert the Child node having an id of 123 at index 4 (i.e, make it the 5th child):

      MATCH (p:Parent {name:"Fred"})
      MATCH (p)-[:Foo*3]->()-[r:Foo]->(c:Child)
      OPTIONAL MATCH (c)-[r1:Foo]->(c1:Child)
      WITH c, r1, COLLECT(c1) AS c1s
      MERGE (cNew:Child {id:123})
      CREATE (c)-[rNew:Foo]->(cNew)
      FOREACH (x IN c1s | 
        CREATE (cNew)-[:Foo]->(x)
        DELETE r1)
      RETURN c, rNew, cNew;
      
    3. To replace the Child at index 4 (i.e, the 5th child) with the Child having an id of 123:

      MATCH (p:Parent { name:"Fred" })
      MATCH (p)-[:Foo*4]->(c0)-[r:Foo]->(c:Child)
      OPTIONAL MATCH (c)-[r1:Foo]->(c1:Child)
      WITH c0, r, c, r1, COLLECT(c1) AS c1s
      MERGE (cNew:Child { id:123 })
      CREATE (c0)-[rNew:Foo]->(cNew)
      DELETE r, c
      FOREACH (x IN c1s | 
         CREATE (cNew)-[:Foo]->(x)
         DELETE r1)
      RETURN c0, rNew, cNew;
      

      Note: The DELETE r, c clause always deletes the node being replaced (c). That is only suitable if that is what you actually want to happen, and will only succeed if c does not have relationships other than r. To explore how to address more specific needs, please ask a new question.

    0 讨论(0)
  • 2021-01-26 07:50

    If I'm following, your nodes may belong to multiple linked lists. A simple 'next' relation is insufficient because when lists cross--share a child node--the 'next' relations will drag in all the downstream nodes of both lists. So you're making the 'next' relations unique to each list by adding the id of the parent node. (Note using the metadata id may lead to issues down the road.)

    So you might have a parent p1 whose id=1, and a unique relationship 'n_p1' to link its children, and a child 'c' whose id=21 you want to add.

    For the parent with no child you could add your new child by:

    MATCH (c {id:21}), (p {id:1}) WHERE NOT p-[:n_p1]->() MERGE p-[:n_p1]->c
    

    And if the parent has one or more children, find the last one that's not the same as the one being added:

    MATCH (c {id:21}), (p {id:1})-[:n_p1*1..5]->(cn) WHERE NOT cn-[:n_p1]->() AND NOT cn.id=c.id MERGE cn-[:n_p1]->c
    

    Somebody else might have a better way, but you could UNION these together. Remember the parts of a UNION must return the same columns, so just return the new child c. The whole thing might look like this:

    MATCH (c {id:21}), (p {id:1}) WHERE NOT p-[:n_p1]->() MERGE p-[:n_p1]->c return c UNION MATCH (c {id:21}), (p {id:1})-[:n_p1*1..5]->(cn) WHERE NOT cn-[:n_p1]->() AND NOT cn.id=c.id MERGE cn-[:n_p1]->c return c; 
    
    0 讨论(0)
提交回复
热议问题