Recursive path solver


(Hagen Ivar) #1

Hi!

I have a tree structure where ids are a list of parameters. For example ["A","B"]. IIf both these parameters are used as input it will fetch next node in tree and so on.
This is the code and an image of the nodes.

CREATE (t1:Tree {id:["A","B"]})
CREATE (t2:Tree {id:["C"]})
CREATE (t3:Tree {id:["D"]})
CREATE (t1)-[:INCLUSION]->(t2)
CREATE (t2)-[:INCLUSION]->(t3)
CREATE (t4:Tree {id:["E"]})
CREATE (t5:Tree {id:["F"]})
CREATE (t4)-[:INCLUSION]->(t5)
CREATE (t6:Tree {id:["D","F"]})
CREATE (t7:Tree {id:["X"]})
CREATE (t6)-[:INCLUSION]->(t7)

Tree%20INCLUSION

In this scenario with input ["A","B","E"] this will then include "C", "D" and "F". For the node A,B it means that both A and B needs to be part of input for the INCLUSION to be valid.
So when we have both "D" AND "F" it should also include "X".
Can this be done with one query?
I have tried to do the same query multiple times and if there is no new nodes discovered between two runs then I have completed discovery. But there must be a better solution right?

WITH ["A","B","E"] AS input
MATCH path=(t:Tree)-[:INCLUSION*]->(p) WHERE ALL(p IN t.id WHERE p IN input)
WITH input, COLLECT(DISTINCT p.id[0]) AS found
WITH found, input, FILTER(p IN found WHERE NOT p IN input) as foundnew
WITH input, found, foundnew, input + foundnew as output,
    CASE (size(foundnew) > 0) 
    WHEN true THEN 
        {status: 'notdone', parameters: input + FILTER(p IN found WHERE NOT p IN input) }
    ELSE 
        {status: 'done', parameters: input }
    END AS res
WITH 
 CASE res.status = "notdone" 
 WHEN true THEN
  res
END AS input,
 CASE res.status = "done" 
 WHEN true THEN
  res
END AS completed

WITH input.parameters AS input, COLLECT(completed) AS allcompleted

OPTIONAL MATCH path=(t:Tree)-[:INCLUSION*]->(p) WHERE ALL(p IN t.id WHERE p IN input)
WITH allcompleted, input, COLLECT(DISTINCT p.id[0]) AS found
WITH allcompleted, found, input, FILTER(p IN found WHERE NOT p IN input) as foundnew
WITH allcompleted, input, found, foundnew, input + foundnew as output,
    CASE (size(foundnew) > 0) 
    WHEN true THEN 
        {status: 'notdone', parameters: input + FILTER(p IN found WHERE NOT p IN input) }
    ELSE 
        {status: 'done', parameters: input }
    END AS res
WITH allcompleted, res.status AS status, res.parameters AS parameters,
 CASE res.status = "notdone" 
 WHEN true THEN
  res
END AS input,
 CASE res.status = "done" 
 WHEN true THEN
  res
END AS completed

WITH input.parameters AS input, COLLECT(completed)+allcompleted AS allcompleted

OPTIONAL MATCH path=(t:Tree)-[:INCLUSION*]->(p) WHERE ALL(p IN t.id WHERE p IN input)
WITH allcompleted, input, COLLECT(DISTINCT p.id[0]) AS found
WITH allcompleted, found, input, FILTER(p IN found WHERE NOT p IN input) as foundnew
WITH allcompleted, input, found, foundnew, input + foundnew as output,
    CASE (size(foundnew) > 0) 
    WHEN true THEN 
        {status: 'notdone', parameters: input + FILTER(p IN found WHERE NOT p IN input) }
    ELSE 
        {status: 'done', parameters: input }
    END AS res
WITH allcompleted, res.status AS status, res.parameters AS parameters,
 CASE res.status = "notdone" 
 WHEN true THEN
  res
END AS input,
 CASE res.status = "done" 
 WHEN true THEN
  res
END AS completed

WITH input.parameters AS input, COLLECT(completed)+allcompleted AS allcompleted

RETURN *

This will return this : (first run finds "C", "D", "F". Second run finds "X" and third run finds no new nodes thus the discovery is completed).

allcompleted	
[
{
  "status": "done",
  "parameters": [
    "A",
    "B",
    "E",
    "C",
    "D",
    "F",
    "X"
  ]
}
]