简体   繁体   中英

Creating directed edges between nodes based on Time property in Neo4j

I am new to Neo4j and Cypher and while converting our Company's Relational DB to Graph Based Model I encountered a problem and I would appreciate any answer.

I have nodes with type person in my model like this:

 (:Person {Fname: 'John', catID: 1})
 (:Person {Fname: 'George', catID: 2})
 (:Person {Fname: 'Natalie', catID: 3})

......

I also have time based Category nodes like this:

(:Category {Id: 1, Date: '2015-02-05'})
(:Category {Id: 1, Date: '2015-01-05'})
(:Category {Id: 1, Date: '2015-03-10'})
(:Category {Id: 3, Date: '2014-03-10'})
(:Category {Id: 3, Date: '2015-05-10'})

......

Now I want to created direct edges from each person to the node in its category with minimum date. What I mean in the above example:

 (:Person {Fname: 'John', catID: 1}) --->  (:Category {Id: 1, Date: '2015-01-05'})

 (:Person {Fname: 'Natalie', catID: 3}) --->  (:Category {Id: 3, Date: '2014-03-10'})

and after that, I want to create directed edges between nodes in each category based on their Date property in an ascending order. I mean:

 (:Category {Id: 1, Date: '2015-01-05'}) ---> (:Category {Id: 1, Date: '2015-02-05'}) ---> (:Category {Id: 1, Date: '2015-03-10'})

 (:Category {Id: 3, Date: '2014-03-10'}) ---> (:Category {Id: 3, Date: '2015-05-10'})

What is the cypher code required to do these things. Thanks a lot in advance

Here's how you'd do the first part of your question, attaching people to their corresponding category nodes with the minimum date:

MATCH (p:Person)
MATCH (c:Category)
WHERE p.catID = c.Id
WITH p, c
ORDER BY p.Fname, c.Date
WITH p, HEAD(COLLECT(c)) AS most_recent
MERGE (p)-[:IN_CATEGORY]->(most_recent)

Now we can do:

MATCH (p:Person)-[:IN_CATEGORY]->(c:Category)
RETURN p.Fname, c.Date

And we get the result:

p.Fname   c.Date
John      2015-01-05
Natalie   2014-03-10

To answer your second question, we can do this:

MATCH (c:Category) WITH c
ORDER BY c.Id, c.Date
WITH c.Id AS id, 
     COLLECT(c) AS categories, 
     COUNT(c) AS count 
UNWIND range(1, count - 1) AS idx
WITH categories[idx - 1] AS from , categories[idx] AS to
CREATE (from)-[:NEXT]->(to);

I stole a few ideas from Michael's answer on that one. :) You can now write queries like this:

MATCH p = (:Person)-[:IN_CATEGORY]->(:Category)-[:NEXT*]->(:Category)
RETURN p

Check out the finished product here: http://console.neo4j.org/r/999rzg

It is almost straightforward :)

Creating a linked list of nodes ordered by timestamp

MATCH (c:Category)
WITH c order by c.Date
// ordered list
WITH collect(c) as cats 
// index for collection
UNWIND range(1,size(cats)-1) as idx
// subsequent entries
WITH cats[idx-1] as first, cats[idx] as second
CREATE (first)-[:NEXT]->(second)
RETURN count(*);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM