Search code examples
neo4jcypher

Collect decorating nodes based on if else conditions


Say I have the following graph:

                    (r1:R)  (r11:R)
                      |     /
                    (p1:P)
                       |
(a1:A) -> (b1:B) -> (c1:C) -> (d1:D)
   \                            |
     - -> (x1:X) -> (y1:Y) -> (c11:C)
            |                    |
          (p11:P)             (p111:P)
            |                    |
          (r111:R)            (r1111:R)


                    (r2:R)
                      |
                    (p2:P)
                      |
(a2:A) -> (b2:B) -> (c2:C) -> (d2:D)


(a3:A) -> (x3:X) -> (y3:Y) -> (c3:C) -> (d3:D)
            |                   |
          (p3:P)              (p33:P)
            |                   |
          (r3:R)              (r33:R)

and I can use this query to get path based on specific rules and merge paths based on the D node attribute name into subgraphs

MATCH (a:A), (d:D)
OPTIONAL MATCH p1=((a)-->(:B)-->(:C)-->(d))
OPTIONAL MATCH p2=((a)-->(:X)-->(:Y)-->(:C)-->(d))

WITH d.name AS dName,
       apoc.coll.toSet(
            apoc.coll.flatten(
                 COLLECT(COALESCE(nodes(p1),[]) + COALESCE(nodes(p2),[]))
            )
       ) AS nodes,
apoc.coll.toSet(
            apoc.coll.flatten(
                 COLLECT(COALESCE(relationships(p1),[]) + COALESCE(relationships(p2),[]))
            )
       ) AS relationships
WHERE nodes <> []
WITH nodes, relationships,
     [src IN nodes WHERE src:X OR src:C |
              {
                SRC: src,
                P: HEAD([(src)--(p:P) | p]),
                R: [(src)--(p:P)--(r:R) | r]
              }
     ] AS srcs

RETURN nodes, relationships, srcs

Notice for C and X nodes, these are decorating nodes P and R. There is always a P node decorating C node and a P node decorating X node. There can be at least one R nodes decorating P nodes.

One very important thing: The above query will collect P and R nodes from both node X and C when the path contains both X and C. But when the path has X node, I only want to get the P and R nodes that decorate the X node and not the C node.

How should I modify the query?


Solution

  • To handle the condition, you can just change the latter part of your query to this

    WITH nodes, relationships,
         CASE WHEN ANY(node IN nodes WHERE node:X) THEN
               [src IN nodes WHERE src:X  |
                        {
                          SRC: src,
                          P: HEAD([(src)--(p:P) | p]),
                          R: [(src)--(p:P)--(r:R) | r]
                        }
               ] 
            ELSE        
               [src IN nodes WHERE src:X OR src:C |
                        {
                          SRC: src,
                          P: HEAD([(src)--(p:P) | p]),
                          R: [(src)--(p:P)--(r:R) | r]
                        }
               ] 
          END AS srcs