2
votes

I have a hierarchy of categories that I want to query using cypher - one query which will return the list of item, with the relationships between them as sub lists.

I am creating my items like this:

 CREATE (C1:Category {name:"Sport"})
 CREATE (C1A:Category {name:"NHL"})
 CREATE (C1B:Category {name:"NBA"})
 CREATE (C1C:Category {name:"NFL"})
 CREATE (C1)-[:SUB_CATEGORY]->(C1A)
 CREATE (C1)-[:SUB_CATEGORY]->(C1B)
 CREATE (C1)-[:SUB_CATEGORY]->(C1C)

 CREATE (C2:Category {name:"Music"})
 CREATE (C2A:Category {name:"Rock"})
 CREATE (C2B:Category {name:"Pop"})
 CREATE (C2C:Category {name:"Classic"})
 CREATE (C2)-[:SUB_CATEGORY]->(C2A)
 CREATE (C2)-[:SUB_CATEGORY]->(C2B)
 CREATE (C2)-[:SUB_CATEGORY]->(C2C)

I want the query to return something like:

{categories:[{name:music,id:1,categories:[{name:rock,id:2},{name:pop,id:3}]]...{name:sport,id:10,categories:[{name:nhl...} 

which I can use to populate drop downs for selecting a category / sub category. (I want to query the entire tree in one query and not one by one at this point)

Another question (for cases where I would like to query partial parts of the tree):

How can get all the main categories (ones who are NOT sub categories of another category...)

1

1 Answers

2
votes

So there's not a perfect answer... You can return all of the data, but it will be in tabular format and you'll need to turn it into a hierarchical format yourself:

MATCH path=(root:Category)-[:SUB_CATEGORY*1..10]->(descendent:Category)
WHERE NOT(()-[:SUB_CATEGORY]->(root))
RETURN nodes(path) AS nodes

Alternatively you can reduce the amount of data that you need to return by finding all parents and children and then combining them in memory with your programming language of choice:

MATCH (parent:Category)-[:SUB_CATEGORY]->(child:Category)
RETURN parent, child

You can also create a Neo4j unmanaged extension (basically a plugin for your Neo4j database) which will let you write some Java code to return this.

As to your last question, it's pretty much answered about, but more directly it's this:

MATCH (root:Category)
WHERE NOT(()-[:SUB_CATEGORY]->(root))
RETURN root

EDIT:

I just realized that you might not have an arbitrarily deep try. If it's just three levels (and also if it's always exactly three levels), you could do:

MATCH (root:Category)-[:SUB_CATEGORY]->(parent:Category)-[:SUB_CATEGORY]->(child:Category)
WITH root, {category: parent, children: collect(child)} AS parent_with_children
RETURN {category: root, children: collect(parent_with_children)}