Neo4J, how to query hierarchical data / PHP

514 Views Asked by At

i created a category-structure in graph-database "neo4j". I have nodes and relationships, everything perfect.

I am using Neoxygen Neoclient for PHP to access the data. How can I query the whole category-graph in an efficient way (including structure) from my root-element?

MATCH (a:`Category`{category_id:0})-[r:HAS_CHILD*]->(b:`Category`)
RETURN b,r

My desired structure in PHP is: - Root --- Category A -------- Subcategory AB --- Category B --- Category C -------- Subcategory CA ----------------- Subsubcategory CAA ...

Any ideas?

Thanks in advance.

mr_g

3

There are 3 best solutions below

1
On

Cypher returns tabular data so if you want to get a tree hierarchy the most efficient way is to return all of the paths from the root to the leaves. A path is a collection/array of node-(relationship-node)* (that is it's an odd number of objects, always containing a node at each end with alternating nodes and relationships). Here is the cypher for how you would do that:

MATCH path(a:`Category`{category_id:0})-[r:HAS_CHILD*]->(b:`Category`)
WHERE NOT(b-[:HAS_CHILD]->())
RETURN b,r

The WHERE clause ensures that you only return all of the paths to the leafs. You could return all categories in the tree which would give you the partial paths too, but all of those partial paths are contained in some longer path so you'd just end up returning more data than you need.

Once you have the paths (I'm not sure what form they show up in Neoclient as I'm not a PHP guy) you can build a hierarchical data structure in memory from the results. If I recall correctly the map/dictionary-type structure in PHP is an associative array.

0
On

It is totally feasible and user-friendly in Neoxygen's NeoClient.

The first thing to make sure, is that you activate the response formatter :

$client = ClientBuilder::create()
   ->setAutoFormatResponse(true)
   ->addConnection(xxx...)
   ->build();

Secondly, concerning your query I would definitely set a depth limit to avoid memory behaviors depending of your graph connectedness :

MATCH (a:`Category`{category_id:0})-[r:HAS_CHILD*..20]->(b:`Category`)
RETURN b,r

Then, you can send it with the client and benefit that the client will remap the results in a graph structure :

$query = 'MATCH (a:`Category`{category_id:{id}})-[r:HAS_CHILD*..20]->(b:`Category`)'
RETURN b,r';
$children = $client->sendCypherQuery($q, ['id'=>0])->getResult()->getNodes();

Now, each node will know what he has as relationships and relationships know their start and end nodes, example :

$children are nodes in the first depth, so

$rels = $children->getOutboundRelationships();
$nodes = [];
foreach ($rels as $rel) {
  $nodes[] = $rel->getEndNode();
}

$nodes holds now all the nodes in depth 2.

There is, currently, no method to get directly the connected nodes from a node object without getting first the relationship, maybe something I can add to the client.

0
On

Schema:

Indexes
  ON :Category(category_id)   ONLINE (for uniqueness constraint) 

Constraints
  ON (category:Category) ASSERT category.category_id IS UNIQUE

Query:

MATCH(c:Category) RETURN c