I have 4 types of nodes: S, G, R
and C
S
nodes have an idStr
property that identifies them.
Every node of type G
uses just a S
node: (:G)-[:USES]->(:S)
Every node of type C
may be connected to multiple R
or G
nodes: (:C)-[:CONNECTED_TO]->(:R|:G)
Every node of type R
may be connected to multiple R
or G
nodes: (:R)-[:CONNECTED_TO]->(:R|:G)
Question:
Given an idStr
range, I want to get all R
and C
nodes that are connected (directly or indirectly) only to G
nodes that use S
nodes with an idStr
in that range.
The closest approach I have achieved is:
MATCH (a:S)<-[:USES]-(b:G)<-[:CONNECTED_TO*]-(n:C)
WHERE a.idStr IN ['1a','b2','something']
WITH COLLECT(DISTINCT b) AS GroupGs
MATCH p=(n)-[:CONNECTED_TO*]->(c:G)
WITH FILTER(x IN NODES(p) WHERE NOT x:G) AS cs,GroupGs,COLLECT(c) AS gs
WHERE ALL(x IN gs WHERE x IN GroupGs)
RETURN cs
but still some nodes that are connected to G
nodes that use S
nodes not in the range are being returned. [Neo4j Console Test]
What am I trying to do?
First match is used to get two things: G
nodes that use S
nodes with idStr
in the given range (GroupGs
) and the C
nodes that are connected to those G
nodes.
Once we get that, we have to check if those C
nodes are connected to more G
nodes (directly or through R
nodes). That is the second match.
Now we have to check for each C
node if all the G
nodes connected to it (directly or through R
nodes) are in the GroupGs
range. If it is so, that C
node (and the R
nodes in the paths to the G
nodes) are a match, and that is what I am trying to get.
Second approach (suggested by @FrobberOfBits)
Trying to use just one match, so we are sure the n
node is the same in the matching:
MATCH (a:S)<-[:USES]-(b:G)<-[:CONNECTED_TO*]-(n:C), p=(n)-[:CONNECTED_TO*]->(c:G)
WHERE a.idStr IN ['1a','b2','something']
WITH COLLECT(DISTINCT b) AS GroupGs, FILTER(x IN NODES(p) WHERE NOT x:G) AS cs,COLLECT(c) AS gs
WHERE ALL(x IN gs WHERE x IN GroupGs)
RETURN cs
The result is the same. [Neo4j Console Test]
Third approach (suggested by @FrobberOfBits)
Giving semantics to the problem, C
may be an endpoint
in a network, R
a repeater
, G
a gateway
and S
a Sim
card.
Sim
nodes have an iccid
property that identifies them.
Every node of type Gateway
uses just a Sim
node: (:Gateway)-[:USES]->(:Sim)
Every node of type Endpoint
may be connected to multiple Repeater
or Gateway
nodes: (:Endpoint)-[:CONNECTED_TO]->(:Repeater|:Gateway)
Every node of type Repeater
may be connected to multiple Repeater
or Gateway
nodes: (:Repeater)-[:CONNECTED_TO]->(:Repeater|:Gateway)
I am trying to get all the Repeater
and Endpoint
nodes that are just connected to Gateway
nodes that are using Sim
nodes whose iccid
are in a range.
Any idea about what am I doing wrong?