I have a graph that looks like this
A1 A2 A3 A4 A5
\ / \ | /
S1 S2
\ /
E1
There can be many E nodes. But the essence from the above is: It is a one to many mapping between E and S nodes It is a one to many mapping between S and A nodes The same S1 can also point to another E node, but I want to extract the following relationship:
For each E node, get all the S nodes and for each S node we get, get all the A nodes.
I know for just E and S, I can do:
match (e:E)<--(s:S)
return e, collect(distinct s)
But I am not sure how to do this with two level of such mapping
Given the following stub data to represent your graph
CREATE (e1:E {id: 'e1'})
CREATE (e2:E {id: 'e2'})
CREATE (s1:S {id: 's1'})
CREATE (s2:S {id: 's2'})
CREATE (a1:A {id: 'a1'})
CREATE (a2:A {id: 'a2'})
CREATE (a3:A {id: 'a3'})
CREATE (a4:A {id: 'a4'})
CREATE (a5:A {id: 'a5'})
CREATE (e1)-[:TO]->(s1)
CREATE (e1)-[:TO]->(s2)
CREATE (s1)-[:TO]->(a1)
CREATE (s1)-[:TO]->(a2)
CREATE (s2)-[:TO]->(a3)
CREATE (s2)-[:TO]->(a4)
CREATE (s2)-[:TO]->(a5)
CREATE (e2)-[:TO]->(s2)
You can retrieve paths from E to A simply by aliasing the full pattern
MATCH path=(e:E)-->(:S)-->(:A)
RETURN path
This will give you a full path, note that a path is a sequenced list of relationships having a start and end node
Graph result
Tabular result
╒═══════════════════════════════════════════════════════╕
│"path" │
╞═══════════════════════════════════════════════════════╡
│[{"id":"e1"},{},{"id":"s2"},{"id":"s2"},{},{"id":"a4"}]│
├───────────────────────────────────────────────────────┤
│[{"id":"e1"},{},{"id":"s2"},{"id":"s2"},{},{"id":"a5"}]│
├───────────────────────────────────────────────────────┤
│[{"id":"e1"},{},{"id":"s2"},{"id":"s2"},{},{"id":"a3"}]│
├───────────────────────────────────────────────────────┤
│[{"id":"e1"},{},{"id":"s1"},{"id":"s1"},{},{"id":"a1"}]│
├───────────────────────────────────────────────────────┤
│[{"id":"e1"},{},{"id":"s1"},{"id":"s1"},{},{"id":"a2"}]│
├───────────────────────────────────────────────────────┤
│[{"id":"e2"},{},{"id":"s2"},{"id":"s2"},{},{"id":"a4"}]│
├───────────────────────────────────────────────────────┤
│[{"id":"e2"},{},{"id":"s2"},{"id":"s2"},{},{"id":"a5"}]│
├───────────────────────────────────────────────────────┤
│[{"id":"e2"},{},{"id":"s2"},{"id":"s2"},{},{"id":"a3"}]│
└───────────────────────────────────────────────────────┘
To maybe make it more clear, let's limit the result to only one path
MATCH path=(e:E)-->(:S)-->(:A)
RETURN path
LIMIT 1
Tabular result
╒═══════════════════════════════════════════════════════╕
│"path" │
╞═══════════════════════════════════════════════════════╡
│[{"id":"e1"},{},{"id":"s2"},{"id":"s2"},{},{"id":"a4"}]│
└───────────────────────────────────────────────────────┘
You can now collect paths per E
node
MATCH path=(e:E)-->(:S)-->(:A)
RETURN e, collect(path) AS paths
The graph result would be similar since it returns all nodes and rels, but the tabular result shows now the aggregation
╒═══════════╤══════════════════════════════════════════════════════════════════════╕
│"e" │"paths" │
╞═══════════╪══════════════════════════════════════════════════════════════════════╡
│{"id":"e1"}│[[{"id":"e1"},{},{"id":"s2"},{"id":"s2"},{},{"id":"a4"}],[{"id":"e1"},│
│ │{},{"id":"s2"},{"id":"s2"},{},{"id":"a5"}],[{"id":"e1"},{},{"id":"s2"}│
│ │,{"id":"s2"},{},{"id":"a3"}],[{"id":"e1"},{},{"id":"s1"},{"id":"s1"},{│
│ │},{"id":"a1"}],[{"id":"e1"},{},{"id":"s1"},{"id":"s1"},{},{"id":"a2"}]│
│ │] │
├───────────┼──────────────────────────────────────────────────────────────────────┤
│{"id":"e2"}│[[{"id":"e2"},{},{"id":"s2"},{"id":"s2"},{},{"id":"a4"}],[{"id":"e2"},│
│ │{},{"id":"s2"},{"id":"s2"},{},{"id":"a5"}],[{"id":"e2"},{},{"id":"s2"}│
│ │,{"id":"s2"},{},{"id":"a3"}]] │
└───────────┴──────────────────────────────────────────────────────────────────────┘
So far we returned full paths. You can extract nodes only from them using the nodes()
function
MATCH path=(e:E)-->(:S)-->(:A)
RETURN nodes(path)
╒═════════════════════════════════════╕
│"nodes(path)" │
╞═════════════════════════════════════╡
│[{"id":"e1"},{"id":"s2"},{"id":"a4"}]│
├─────────────────────────────────────┤
│[{"id":"e1"},{"id":"s2"},{"id":"a5"}]│
├─────────────────────────────────────┤
│[{"id":"e1"},{"id":"s2"},{"id":"a3"}]│
├─────────────────────────────────────┤
│[{"id":"e1"},{"id":"s1"},{"id":"a1"}]│
├─────────────────────────────────────┤
│[{"id":"e1"},{"id":"s1"},{"id":"a2"}]│
├─────────────────────────────────────┤
│[{"id":"e2"},{"id":"s2"},{"id":"a4"}]│
├─────────────────────────────────────┤
│[{"id":"e2"},{"id":"s2"},{"id":"a5"}]│
├─────────────────────────────────────┤
│[{"id":"e2"},{"id":"s2"},{"id":"a3"}]│
└─────────────────────────────────────┘
And now, if you want to return a json tree like structure, you can use map projections
MATCH (e:E)
RETURN
e {.*, s: [(e)-->(s:S) | s{.*, a: [(s)-->(a:A) | a{.*}]}]}
╒══════════════════════════════════════════════════════════════════════╕
│"e" │
╞══════════════════════════════════════════════════════════════════════╡
│{"s":[{"a":[{"id":"a4"},{"id":"a5"},{"id":"a3"}],"id":"s2"},{"a":[{"id│
│":"a1"},{"id":"a2"}],"id":"s1"}],"id":"e1"} │
├──────────────────────────────────────────────────────────────────────┤
│{"s":[{"a":[{"id":"a4"},{"id":"a5"},{"id":"a3"}],"id":"s2"}],"id":"e2"│
│} │
└──────────────────────────────────────────────────────────────────────┘
Let's format the first result a bit
{
"s": [
{
"a": [
{
"id": "a4"
},
{
"id": "a5"
},
{
"id": "a3"
}
],
"id": "s2"
},
{
"a": [
{
"id": "a1"
},
{
"id": "a2"
}
],
"id": "s1"
}
],
"id": "e1"
}
This sounds a bit cryptic but as soon as you understand how it works it is quite powerful, I suggest reading a bit more about it here :