Starting with nodes in blue I want to compare each to the other in blue looking for their first common child nodes.(in green) My current query below is returning the first common node to all starting values and also all the common child nodes. (in red: left-hand graph)
How can I filter the results so only the first common nodes (in green) are returned discarding the white and red nodes.
I am starting with 2 - 10 values and currently can have over 100 result rows when only a couple of their root node(s) are required. I think I need to collect the results then do another pattern match on the collection - Maybe compare the paths looking for the first common node. There may be several root (green) nodes for each starting set.
Thanks for your help!
MATCH (val0:v {value:”532”} )-[r*0..50]->(x:n) WITH x
MATCH (val1:v {value:”234”} )-[r*0..50]->(x:n) WITH x
MATCH (val2:v {value:”678”} )-[r*0..50]->(x:n)
RETURN DISTINCT con
I think you've got the right idea, collecting the results and then doing some other match to find which of those results to keep. I think APOC Procedures can help here, as its path finding procs have ways to stop when reaching certain nodes (the terminatorNodes
config parameter).
You'll also want to collect your results along the way so you don't multiply the amount of work that needs to be done. For example, the number of rows for x
from your first match will multiply the number of times you perform the second match. If we collect results into lists along the way, then we only execute each expansion once instead of multiplicatively per row (Cypher operations execute per row). We can use list intersection (from APOC) to get the nodes in common along the way.
Then we can use the path finder procs to find a path from any of your starting nodes, with a termination node filter so each path explored will stop when we reach one of those common node results (which will be the green nodes you want).
Here's an example that may work for you:
MATCH (val0:v {value:"532"} )-[*0..50]->(x:n)
WITH collect(distinct x) as results
MATCH (val1:v {value:"234"} )-[*0..50]->(x:n)
WITH apoc.coll.intersection(results, collect(distinct x)) as results
MATCH (val2:v {value:"678"} )-[*0..50]->(x:n)
WITH apoc.coll.intersection(results, collect(distinct x)) as results
MATCH (start:v {value:"532"} )
CALL apoc.path.subgraphNodes(start, {terminatorNodes:results}) YIELD node as firstCommon
RETURN firstCommon
EDIT
As far as a non-APOC approach, something like this might work, replacing the apoc.path.subgraphNodes()
call:
...
MATCH p=(start:Root {id:532} )-[*0..50]->(x)
WHERE x in results and single(node in nodes(p) where node in results)
RETURN distinct x