7.11. Implementing newsfeeds in a graph

cypher-newsfeed-graph.svg

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:

  1. First Get the list of all my friends (along with me) through 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.
  2. Get the latest status update of my friends through Status relationship (MATCH myfriend-[:STATUS]-latestupdate).
  3. Get subsequent status updates (along with the latest one) of my friends through NEXT relationships (MATCH myfriend-[:STATUS]-latestupdate-[:NEXT*0..1]-statusupdates).
  4. Sort the status updates by posted date (ORDER BY statusupdates.date DESC).
  5. LIMIT the number of updates you need in every query (LIMIT x SKIP x*y).

Result

namedatetext
0 row
0 ms

(empty result)


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:

  1. Get the latest update (if it exists) of the user through the STATUS relationship (MATCH me-[r?:STATUS]-secondlatestupdate).
  2. Delete the 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).
  3. Now, create the new 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})).
  4. Now, create a 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
0 ms

"Status"


cypher-insertstatusupdate-graph.svg