Aeveus
Aeveus

Reputation: 5382

Limiting nodes per label

I have a graph with currently around the several thousand nodes with each node having between two to ten relationships. If we look at a single node and its connections, they would look like somewhat this: Node and relating nodes

The nodes with alphabetical characters are category nodes. All other nodes are content nodes that have an associated with relationship with these category nodes and their colour denotes which label(s) is/are attached to it. For simplicity, every node has a single label, and each node is only connected to a single other node:

Now, the simplest thing I'm trying to do is getting a certain amount of related content nodes to a given node. The following returns all twenty related nodes:

START n = node(1)
MATCH (n)-->(category)<--(m)
RETURN m

However, I would like to filter this to 2 nodes per label per category (and afterwards play with ordering by nodes that have multiple categories overlapping with the starting node.

Currently I'm doing this by getting the results from the above query, and then manually looping through the results, but this feels like redundant work to me.

Is there a way to do this via Neo4j's Cipher Query language?

Upvotes: 3

Views: 619

Answers (2)

cybersam
cybersam

Reputation: 67044

This answer extends @Stefan's original answer to return the result for all the categories, not just one of them.

START p = node(1)
MATCH (p)-->(category)<--(m)
WITH category, labels(m) as label, collect(m)[0..2] as nodes 
UNWIND label as lbl
UNWIND nodes AS n
RETURN category, lbl, n

To facilitate manual verification of the results, you can also add this line to the end, to sort the results. (This sorting should probably not be in your final code, unless you really need sorted results and are willing expend the extra computing time):

ORDER BY id(category), lbl

Upvotes: 3

Stefan Armbruster
Stefan Armbruster

Reputation: 39925

Cypher has a labels function returning an array with all labels for a given node. Assuming you only have exactly one label per m node the following approach could work:

START n = node(1)
MATCH (n)-->(category)<--(m)
WITH labels(m)[0] as label, collect[m][0..2] as nodes 
UNWIND nodes as n
RETURN n

The WITH statements builds up a seperate collection of all nodes sharing the same label. Using the subscript operator [0..2] the collection just keeps the first two elements. Unwind then converts the collection into separate rows for the result. From here on you can apply ordering.

Upvotes: 3

Related Questions