Implementation of newsfeed or timeline feature is a frequent requirement for social applications. The following exmaples are inspired by Newsfeed feature powered by Neo4j Graph Database. The query asked here is:
Starting at me
, retrieve the time-ordered status feed of the status updates of me and and all friends that are connected via a CONFIRMED
FRIEND
relationship to me.
Query.
START me=node:node_auto_index(name='Joe') MATCH me-[rels:FRIEND*0..1]-myfriend WHERE ALL(r in rels WHERE r.status = 'CONFIRMED') WITH myfriend MATCH myfriend-[:STATUS]-latestupdate-[:NEXT*0..1]-statusupdates RETURN myfriend.name as name, statusupdates.date as date, statusupdates.text as text ORDER BY statusupdates.date DESC LIMIT 3
To understand the strategy, let’s divide the query into five steps:
FRIEND
relationship (MATCH me-[rels:FRIEND*0..1]-myfriend
). Also, the WHERE
predicate can be added to check whether the friend request is pending or confirmed.
MATCH myfriend-[:STATUS]-latestupdate
).
NEXT
relationships (MATCH myfriend-[:STATUS]-latestupdate-[:NEXT*0..1]-statusupdates
) which will give you the latest and one additional statusupdate, adjust 0..1
to whatever suits your case.
ORDER BY statusupdates.date DESC
).
LIMIT
the number of updates you need in every query (LIMIT x SKIP x*y
).
Try this query live. (1) {"name":"Bob"} (2) {"date":1,"name":"bob_s1","text":"bobs status1"} (3) {"date":4,"name":"bob_s2","text":"bobs status2"} (4) {"name":"Alice"} (5) {"date":2,"name":"alice_s1","text":"Alices status1"} (6) {"date":5,"name":"alice_s2","text":"Alices status2"} (7) {"name":"Joe"} (8) {"date":3,"name":"joe_s1","text":"Joe status1"} (9) {"date":6,"name":"joe_s2","text":"Joe status2"} (1)-[:STATUS]->(2) {} (1)-[:FRIEND]->(4) {"status":"CONFIRMED"} (2)-[:NEXT]->(3) {} (4)-[:STATUS]->(5) {} (4)-[:FRIEND]->(7) {"status":"PENDING"} (5)-[:NEXT]->(6) {} (7)-[:STATUS]->(8) {} (7)-[:FRIEND]->(1) {"status":"CONFIRMED"} (8)-[:NEXT]->(9) {} START me=node:node_auto_index(name='Joe') MATCH me-[rels:FRIEND*0..1]-myfriend WHERE ALL(r in rels WHERE r.status = 'CONFIRMED') WITH myfriend MATCH myfriend-[:STATUS]-latestupdate-[:NEXT*0..1]-statusupdates RETURN myfriend.name as name, statusupdates.date as date, statusupdates.text as text ORDER BY statusupdates.date DESC LIMIT 3
Here, the example shows how to add a new status update into the existing data for a user.
Query.
START me=node:node_auto_index(name='Bob') MATCH me-[r?:STATUS]-secondlatestupdate DELETE r WITH me, secondlatestupdate CREATE me-[:STATUS]->(latest_update{text:'Status',date:123}) WITH latest_update,secondlatestupdate CREATE latest_update-[:NEXT]-secondlatestupdate WHERE secondlatestupdate <> null RETURN latest_update.text as new_status
Dividing the query into steps, this query resembles adding new item in middle of a doubly linked list:
STATUS
relationship (MATCH me-[r?:STATUS]-secondlatestupdate
).
STATUS
relationship between user
and secondlatestupdate
(if it exists), as this would become the second latest update now and only the latest update would be added through a STATUS
relationship, all earlier updates would be connected to their subsequent updates through a NEXT
relationship. (DELETE r
).
statusupdate
node (with text and date as properties) and connect this with the user through a STATUS
relationship (CREATE me-[:STATUS]->(latest_update{text:'Status',date:123})
).
NEXT
relationship between the latest status update and the second latest status update (if it exists) (CREATE latest_update-[:NEXT]-secondlatestupdate WHERE secondlatestupdate <> null
).
Result
new_status |
---|
1 row |
Nodes created: 1 |
Relationships created: 2 |
Properties set: 2 |
Relationships deleted: 1 |
|
Try this query live. (1) {"name":"Bob"} (2) {"date":1,"name":"bob_s1","text":"bobs status1"} (3) {"date":4,"name":"bob_s2","text":"bobs status2"} (1)-[:STATUS]->(2) {} (2)-[:NEXT]->(3) {} START me=node:node_auto_index(name='Bob') MATCH me-[r?:STATUS]-secondlatestupdate DELETE r WITH me, secondlatestupdate CREATE me-[:STATUS]->(latest_update{text:'Status',date:123}) WITH latest_update,secondlatestupdate CREATE latest_update-[:NEXT]-secondlatestupdate WHERE secondlatestupdate <> null RETURN latest_update.text as new_status
Copyright © 2013 Neo Technology