Search code examples
neo4jcypher

Get different decorating nodes from a complex subgraph relationship


Say I have the following graph:

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


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


(a3:A) -> (x3:X) -> (y3:Y) -> (d3:D)
            |
          (p3:P)
            |
          (r3: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)-->(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 <> []

RETURN nodes, relationships

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

Now for my desirable query return, for each node, relationships, i would also like to get an array of json object of P, R and the nodes that P is decorating. More concretely, the return of the above graph becomes

   row1: nodes(a1, b1, c1, d1, x1, y1), relationships(a1, b1, c1, d1, x1, y1), [{SRC:c1, P: p1, R:[r1, r11]}, {SRC:x1, P:p11, R:[r111]}]
   row2: nodes(a2, b2, c2, d2), relationships(a2, b2, c2, d2), [{SRC:c2, P:p2, R:[r2]}]
   row3: nodes(a3, x3, y3, d3), relationships(a3, x3, y3, d3), [{SRC:x3, P:p3, R:[r3]}]

How should I change my query? NOTE: for the SRC,P,R structure, I am open for other formats that can help the query to be easier to construct, but it needs to be able to identity the same relationships between SRC,P,R.


Solution

  • Try this:

    MATCH (a:A), (d:D)
    OPTIONAL MATCH p1=((a)-->(:B)-->(:C)-->(d))
    OPTIONAL MATCH p2=((a)-->(:X)-->(:Y)-->(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