Cypher
is not well suited for dumping out graph data in a tree structure when leaves are at arbitrary depths.
However, with neo4j 3.x, you can get close to what you want if you are able to install the APOC plugin on your server and use the apoc.convert.toTree
procedure.
First, let's create some sample data:
CREATE
(c1:Category {name: 'PC'}),
(c1)-[:subcategory]->(c2:Category {name: 'Parts'}),
(c2)-[:subcategory]->(c3:Category {name: 'CPU'}),
(c3)-[:subcategory]->(c4:Category {name: 'CacheRAM'}),
(c1)-[:subcategory]->(c5:Category {name: 'Accessories'}),
(c5)-[:subcategory]->(c6:Category {name: 'Mouse'}),
(c5)-[:subcategory]->(c7:Category {name: 'Keyboard'}),
(c10:Category {name: 'Laptop'}),
(c10)-[:subcategory]->(c20:Category {name: 'Parts'}),
(c20)-[:subcategory]->(c30:Category {name: 'CPU'}),
(c10)-[:subcategory]->(c40:Category {name: 'Accessories'}),
(c40)-[:subcategory]->(c50:Category {name: 'Stylus'});
Then with this query:
MATCH p=(n:Category)-[:subcategory*]->(m)
WHERE NOT ()-[:subcategory]->(n)
WITH COLLECT(p) AS ps
CALL apoc.convert.toTree(ps) yield value
RETURN value;
... you will get N result rows, where N is the number of root Category
nodes. Here is a snippet of sample results:
{
...
"row": [
{
"_id": 150,
"_type": "Category",
"name": "PC",
"subcategory": [
{
"_id": 154,
"_type": "Category",
"name": "Accessories",
"subcategory": [
{
"_id": 156,
"_type": "Category",
"name": "Keyboard"
},
{
"_id": 155,
"_type": "Category",
"name": "Mouse"
}
]
},
{
"_id": 151,
"_type": "Category",
"name": "Parts",
"subcategory": [
{
"_id": 152,
"_type": "Category",
"name": "CPU",
"subcategory": [
{
"_id": 153,
"_type": "Category",
"name": "CacheRAM"
}
]
}
]
}
]
}
],
...
"row": [
{
"_id": 157,
"_type": "Category",
"name": "Laptop",
"subcategory": [
{
"_id": 158,
"_type": "Category",
"name": "Parts",
"subcategory": [
{
"_id": 159,
"_type": "Category",
"name": "CPU"
}
]
},
{
"_id": 160,
"_type": "Category",
"name": "Accessories",
"subcategory": [
{
"_id": 161,
"_type": "Category",
"name": "Stylus"
}
]
}
]
}
],
...
}