Prev |  | Next

## 5.11. Implementing newsfeeds in a graph

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.

    MATCH (me { name: 'Joe' })-[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 {name: 'Joe'})-[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)`) which will give you the latest and one additional statusupdate; adjust `0..1` to whatever suits your case.
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 3`).

Result

name | date | text
--- | --- | ---
3 rows
`"Joe"` | `6` | `"Joe status2"`
`"Bob"` | `4` | `"bobs status2"`
`"Joe"` | `3` | `"Joe status1"`

Here, the example shows how to add a new status update into the existing data for a user.

Query.

    MATCH (me)
    WHERE me.name='Bob'
    OPTIONAL MATCH (me)-[r:STATUS]-(secondlatestupdate)
    DELETE r
    CREATE (me)-[:STATUS]->(latest_update { text:'Status',date:123 })
    WITH latest_update, collect(secondlatestupdate) AS seconds
    FOREACH (x IN seconds | CREATE latest_update-[:NEXT]->x)
    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 (`OPTIONAL 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. Pipe over `statusupdate` or an empty collection to the next query part (`WITH latest_update, collect(secondlatestupdate) AS seconds`).
5. Now, create a `NEXT` relationship between the latest status update and the second latest status update (if it exists) (`FOREACH(x in seconds | CREATE latest_update-[:NEXT]->x)`).

Result

new_status
1 row
Nodes created: 1
Relationships created: 2
Properties set: 2
Relationships deleted: 1
`"Status"`

Copyright © 2014 Neo Technology

Prev | Up | Next
| Home |