SarathSprakash
SarathSprakash

Reputation: 4624

How to limit subnodes from each nodes Neo4j Cypher

I am new to Neo4j,I have the following situation

enter image description here

In the above diagram represented a node with label user with sub-nodes having label shops. Each of these sub-nodes have sub-nodes with label items. Each node items has attribute size and the items node is in descending order by size attribute for each node shops as represented in the figure.

Question

I want to get two items node whose size is less than or equal to 17 from each shops . How to do that? I tried, but its not working the way I need

Here is what I have tried

match (a:user{id:20000})-[:follows]-(b:shops)
with b
match (b)-[:next*]->(c:items)
where c.size<=17
return b
limit 2

Note- These shops node can have thousands of items nodes. So how to find the desired nodes without traversing all thousands of items nodes. Please help , thanks in advance.

Upvotes: 1

Views: 870

Answers (2)

boggle
boggle

Reputation: 221

You can avoid having to traverse all items of each shop by grouping them according to size. In this approach, your graph looks like this

(:User)-[:follows]-(:Shop)-[:sells]-(:Category {size: 17})-[:next]-(:Item)

You could then find two items per shop using

match (a:User {id: 20000})-[:follows]-(s:Shop)-[:sells]-(c:Category)
where c.size <= 17
with *
match p = (c)-[:next*0..2]-()
with s, collect(tail(nodes(p))) AS allCatItems
return s, reduce(shopItems=allCatItems[..0], catItems in allCatItems | shopItems + catItems)[..2]

shopItems=allCatItems[..0] is a workaround for a type checking problem, this essentially initializes shopItems to be an empty Collection of nodes.

Upvotes: 0

Michael Hunger
Michael Hunger

Reputation: 41706

Right now Cypher does not handle this case well enough, I would probably do a java based unmanaged extension for this.

It would look like this:

public List<Node> findItems(Node shop, int size, int count) {
   List<Node> results=new ArrayList<>(count);
   Node item = shop.getSingleRelationship(OUTGOING, "next").getEndNode();
   while (item.getProperty("size") > size && results.size() < count) {
       if (item.getProperty("size") <= size) result.add(item);
       item = item.getSingleRelationship(OUTGOING, "next").getEndNode();
   }
   return result;
}


List<Node> results=new ArrayList<>(count*10);
for (Relationship rel = user.getRelationships(OUTGOING,"follows")) {
   Node shop = rel.getEndNode();
   results.addAll(findItems(shop,size,count));
}

Upvotes: 3

Related Questions