First of all, I'm new to NEO4J and to CYPHER. So I'm twerking here and there to figure out to get the result I want.
Below is my graph. Let's say it's a simple family tree.
I have come up with this simple cypher query to fetch the direct descendants of the node
MATCH (p:Person {username: "SETHLORDM"})<-[r:CHILD_OF]-(p2)
RETURN {current: p, children: collect(p2)}
and the text version of the result is as below
The above is okay, but I want to get the text result as follows if it's doable with NEO4J.
[
{
"username": "SETHLORDM",
"location": "NO_LOCATION",
"children": [
{
"username": "TESTNODE_1",
"location": "LEFT",
"children": [
{
"username": "TESTNODE_3",
"location": "LEFT",
"children": []
},
{
"username": "TESTNODE_4",
"location": "RIGHT",
"children": []
}
],
},
{
"username": "TESTNODE_2",
"location": "RIGHT",
"children": [
{
"username": "TESTNODE_5",
"location": "RIGHT",
"children": []],
},
{
"username": "TESTNODE_6",
"location": "RIGHT",
"children": []],
}
],
}
],
}
]
Any help regarding this would be highly appreciated. Thank you
One way to approach it is using apoc.convert.toTree (using the plugin apoc). This can create the tree structure that you are looking for. But, since your tree is bottom-up, the result will be same, meaning each node will point its parent. If you want to get the results as you want, using this method, you will have to change your relations.
For example, using this data:
MERGE (a:Person{key: 1, username: "SETHLORDM"})
MERGE (b:Person{key: 2})
MERGE (c:Person{key: 3})
MERGE (d:Person{key: 4})
MERGE (e:Person{key: 5})
MERGE (f:Person{key: 6})
MERGE (g:Person{key: 7})
MERGE (b)-[:CHILD_OF]-(a)
MERGE (c)-[:CHILD_OF]-(a)
MERGE (d)-[:CHILD_OF]-(b)
MERGE (e)-[:CHILD_OF]-(b)
MERGE (f)-[:CHILD_OF]-(c)
MERGE (g)-[:CHILD_OF]-(c)
and this query:
MATCH path = (p:Person {username: "SETHLORDM"})<-[r:CHILD_OF*..2]-(p2)
WITH collect(path) AS paths
CALL apoc.convert.toTree(paths)
YIELD value
RETURN value;
will give this result:
"_type": "Person",
"child_of": [
{
"_type": "Person",
"child_of": [
{
"_type": "Person",
"_id": 243,
"key": 5
},
{
"_type": "Person",
"_id": 242,
"key": 4
}
],
"_id": 240,
"key": 2
},
{
"_type": "Person",
"child_of": [
{
"_type": "Person",
"_id": 245,
"key": 7
},
{
"_type": "Person",
"_id": 244,
"key": 6
}
],
"_id": 241,
"key": 3
}
],
"_id": 239,
"key": 1,
"username": "SETHLORDM"
}
But changing the links to this:
MERGE (a)-[:CHILDREN]-(b)
MERGE (a)-[:CHILDREN]-(c)
MERGE (b)-[:CHILDREN]-(d)
MERGE (b)-[:CHILDREN]-(e)
MERGE (c)-[:CHILDREN]-(f)
MERGE (c)-[:CHILDREN]-(g)
And adjusting the query to:
MATCH path = (p:Person {username: "SETHLORDM"})-[r:CHILDREN*..2]->(p2)
WITH collect(path) AS paths
CALL apoc.convert.toTree(paths)
YIELD value
RETURN value;
Will provide:
{
"_type": "Person",
"_id": 246,
"children": [
{
"_type": "Person",
"_id": 247,
"children": [
{
"_type": "Person",
"_id": 249,
"key": 4
},
{
"_type": "Person",
"_id": 250,
"key": 5
}
],
"key": 2
},
{
"_type": "Person",
"_id": 248,
"children": [
{
"_type": "Person",
"_id": 252,
"key": 7
},
{
"_type": "Person",
"_id": 251,
"key": 6
}
],
"key": 3
}
],
"key": 1,
"username": "SETHLORDM"
}
Which is now similar to what you wanted...
Bonus: if you are using apoc, you can replace the MATCH
query by apoc.path.expandConfig
which should be more efficient to larger graphs.