Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Neo4j Cypher: Using LIMIT and COLLECT (or using LIMIT twice in the same query)

Tags:

neo4j

cypher

I have a timeline type query that retrieves posts and athe users who have 'liked' a post.

START me=node:node_auto_index(UserIdentifier='USER0')
MATCH me-[rels:FOLLOWS*0..1]-myfriend
WITH myfriend
MATCH myfriend-[:POSTED*]-statusupdates<-[r?:LIKE]-likers
WHERE myfriend <> statusupdates
RETURN distinct statusupdates, FILTER (x in collect(distinct likers) : x <> null), myfriend
ORDER BY statusupdates.PostTime DESC
LIMIT 25; 

I limit the number of posts that I retrieve to 25. I would also like to limit the number of users who have liked a post. Is there a way to use multiple limit clauses in a query? Ideally I would like to do something like the following:

START me=node:node_auto_index(UserIdentifier='USER0')
MATCH me-[rels:FOLLOWS*0..1]-myfriend
WITH myfriendMATCH myfriend-[:POSTED*]-statusupdates<-[r?:LIKE]-likers
WHERE myfriend <> statusupdates
RETURN distinct statusupdates, LIMIT FILTER (x in collect(distinct likers) : x <> null) 6, myfriend
ORDER BY statusupdates.PostTime DESC
LIMIT 25; 

Or:

START me=node:node_auto_index(UserIdentifier='USER0')
MATCH me-[rels:FOLLOWS*0..1]-myfriend
WITH myfriendMATCH myfriend-[:POSTED*]-statusupdates<-[r?:LIKE]-likers
WHERE myfriend <> statusupdates
RETURN distinct statusupdates, FILTER (x in collect(distinct likers) : x <> null), myfriend
LIMIT likers 6
ORDER BY statusupdates.PostTime DESC
LIMIT 25; 

Which would limit the number of returned likers for each post to 6. How can I achieve this?

like image 541
Aran Mulholland Avatar asked Nov 15 '12 23:11

Aran Mulholland


2 Answers

The trouble with limiting likers is that it's on the other end of the query, so there's no way to optimize that. You basically have to do two matches. Also, the LIMIT after the WITH is only available in 1.9.M01

So, I think this sort of does what you want:

START me=node:node_auto_index(UserIdentifier='USER0')
MATCH me-[rels:FOLLOWS*0..1]-myfriend-[:POSTED*]-statusupdates<-[r?:LIKE]-likers
WITH distinct likers
// you can also order by something here, if you want.
LIMIT 6
START me=node:node_auto_index(UserIdentifier='USER0')
// at this point, likers is already bound, so it's limited to the 6
MATCH me-[rels:FOLLOWS*0..1]-myfriend-[:POSTED*]-statusupdates<-[r?:LIKE]-likers
RETURN distinct statusupdates, likers, myfriend
ORDER BY statusupdates.postTime
LIMIT 25;

Untested code. Hope it works--next time build us a sample in console so we can play around. :)

like image 99
Eve Freeman Avatar answered Oct 14 '22 22:10

Eve Freeman


In Neo4j 2.0 you can use collection slices. I.e. you can do queries similar to

MATCH (n)-[r*0..1]-(x) RETURN n, LABELS(n), COLLECT([x,id(x),LABELS(x),r])[0..10] LIMIT 5

The example above would return up to 5 n-nodes with 0 to 10 related nodes each in the collection.

like image 33
Håkan Löfqvist Avatar answered Oct 14 '22 22:10

Håkan Löfqvist