Reputation: 4624
I am new to Neo4j,I have the following situation
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.
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
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
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