Say I have the following graph:
(a1:A) -> (b1:B) -> (c1:C) -> (d1:D)
\ /
- -> (x1:X) - --> (y1:Y)
(a2:A) -> (b2:B) -> (c2:C) -> (d2:D)
(a3:A) -> (x3:X) -> (y3:Y) -> (d3:D)
The actual graph also contains other relationships between node label A and D. But I am only interested in these relationships between A and D. So I have to force some rules on the path. see query below
match p1=((:A)-->(:B)-->(:C)->(:D))
return p1
match p2=((:A)-->(:X)-->(:Y)->(:D))
return p2
This will return me four rows
a1-b1-c1-d1
a1-x1-y1-d1
a2-b2-c2-d2
a3-x3-y3-d3
But I would like to return an array of subgraphs and merge paths based on the common node attribute D.name. I.e., d1, d2, d3 are differentiated by their node attribute called "name". So the output I would like to have is
// query logic
// return subgraphs, each subgraph is a row. each subgraph contains the unique node and relationships from A to D. If there are multiple paths to the same D, then merge these paths to the same subgraph
More concretely, the return of the above example becomes
row1: nodes(a1, b1, c1, d1, x1, y1), relationships(a1, b1, c1, d1, x1, y1)
row2: nodes(a2, b2, c2, d2), relationships(a2, b2, c2, d2)
row3: nodes(a3, x3, y3, d3), relationships(a3, x3, y3, d3)
What would be the query?
UPDATE: Test graph
merge (a1:A{name: 'a1'})
merge (b1:B{name: 'b1'})
merge (c1:C{name: 'c1'})
merge (d1:D{name: 'd1'})
merge (x1:X{name: 'x1'})
merge (y1:Y{name: 'y1'})
merge (a2:A{name: 'a2'})
merge (b2:B{name: 'b2'})
merge (c2:C{name: 'c2'})
merge (d2:D{name: 'd2'})
merge (a3:A{name: 'a3'})
merge (x3:X{name: 'x3'})
merge (y3:Y{name: 'y3'})
merge (d3:D{name: 'd3'})
merge(a1)-[:TESTS]->(b1)
merge(b1)-[:TESTS]->(c1)
merge(c1)-[:TESTS]->(d1)
merge(a1)-[:TESTS]->(x1)
merge(x1)-[:TESTS]->(y1)
merge(y1)-[:TESTS]->(d1)
merge(a2)-[:TESTS]->(b2)
merge(b2)-[:TESTS]->(c2)
merge(c2)-[:TESTS]->(d2)
merge(a3)-[:TESTS]->(x3)
merge(x3)-[:TESTS]->(y3)
merge(y3)-[:TESTS]->(d3)
It seems that not just the :D
nodes are different, but also the :A
nodes. But, assuming that you want group by d.name
, I guess this does it.
MATCH p=((:A)-[*]->(d:D))
RETURN d.name AS dName,
apoc.coll.toSet(
apoc.coll.flatten(
COLLECT(nodes(p))
)
) AS nodes,
apoc.coll.toSet(
apoc.coll.flatten(
COLLECT(relationships(p))
)
) AS relationships
In case you want to filter for specific paths, you can do something like:
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