Search code examples
neo4jcypherneo4j-graphql-js

How to Splice a Linked Lists in Cypher


I have a Linked-List of LogEntries. Each entry has a date. Every user has exactly 1 Log.

What's the best way to splice in a new log entry if I receive a date in the past?

(log:Log)
(e1:LogEntry {date: Date('2020-03-19')})
(e2:LogEntry {date: Date('2020-03-17')})
…

CREATE (log)-[:PREV_ENTRY]->(e1)
CREATE (e1)-[:PREV_ENTRY]->(e2)
CREATE (e2)-[:PREV_ENTRY]->(e3)
CREATE (e3)-[:PREV_ENTRY]->(e4)

I'm building a public graphql API to trace contact of COVID-19 case: https://github.com/mmmoli/contacttracing.app-graphql-api/blob/master/src/appConfigs/schema.ts#L55

Any help would be awesome!

Inspiration from Max's Fraud post: https://maxdemarzi.com/2019/08/19/finding-fraud/

🙏🏻


Solution

  • Is this when you're first creating the database (i.e. the entries weren't sorted to start) or is this entry appearing later on and you're trying to update/insert with a new entry? If I'm understanding correctly, you want to insert a node in the chain for the log. How about

    EDIT: Included additional constraint to make sure matching the chain finds one set of nodes between which to insert the new entry

    CREATE (eInsert:LogEntry:NewEntry {date: Date('2020-03-18')})
    WITH eInsert
    
    MATCH (log:Log {id: "log1"})
    WITH log, eInsert
    
    MATCH (log)-[:PREV_ENTRY*]->(e1)-[oldLink:PREV_ENTRY]->(e2:LogEntry)
    WHERE e2.date < eInsert.date
      AND e1.date >= eInsert.date 
    WITH e1, e2, eInsert, oldLink
    
    CREATE (e1)-[:PREV_ENTRY]->(eInsert)-[:PREV_ENTRY]->(e2)
    DELETE oldLink
    

    That should work, but for completeness, here's the script I used to create the sample chain

    CREATE (log:Log {id: 'log1'})
    CREATE (e1:LogEntry {date: Date('2020-03-30')})
    CREATE (e2:LogEntry {date: Date('2020-03-28')})
    CREATE (e3:LogEntry {date: Date('2020-03-23')})
    CREATE (e4:LogEntry {date: Date('2020-03-17')})
    CREATE (e5:LogEntry {date: Date('2020-03-09')})
    
    CREATE (log)-[:PREV_ENTRY]->(e1)
    CREATE (e1)-[:PREV_ENTRY]->(e2)
    CREATE (e2)-[:PREV_ENTRY]->(e3)
    CREATE (e3)-[:PREV_ENTRY]->(e4)
    CREATE (e4)-[:PREV_ENTRY]->(e5)