cancel
Showing results for 
Search instead for 
Did you mean: 

Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.

How to create relationships between consecutive nodes based on Date property?

Hi,

I'm trying to create relationships between nodes based on a Date property of thses nodes. A relationship like "NEXT" to visualize a sort of timeline of Nodes.
My graph looks like this :


And I would like to create "NEXT" relationships between "event" Nodes but only if they are linked to the same "topic" Node.

I ran the following cypher request to link the event Nodes for a single topic :

MATCH (e:event)-[r:CONCERNS]-(t:topic {name: 'topic1'})
WITH e ORDER BY e.dateEvent ASC
WITH COLLECT(e) AS events
FOREACH (n IN RANGE(0, SIZE(events)-2) |
FOREACH (prec IN [events[n]] |
FOREACH (next IN [events[n+1]] |
MERGE (prec)-[:NEXT]->(next))));

It workd as you can see here :
image|405x500

Unfortunaely, I didn't found the solution to run it for all the topics without creating a "NEXT" relationship betwwen event Nodes not linked ti the same Topic.

I there someone who could help me ?

Thanks in advance

Olivier

1 ACCEPTED SOLUTION

Try this:

Step 1: Export the topic to a csv file:

CALL apoc.export.csv.query("
MATCH (tops:topic)
with distinct id(tops) as ID, tops.name as topic
RETURN ID, topc", "topics.csv", {})

This csv file will be in 'import' folder.

Step 2: Use LOAD CSV

LOAD CSV WITH HEADERS FROM "file:///topics.csv" AS row
WITH row

MATCH (t:topic) where id(t) = toInteger(row.ID)

MATCH (e:event)-[r:CONCERNS]-(t)
WITH e ORDER BY e.dateEvent ASC
WITH COLLECT(e) AS events
FOREACH (n IN RANGE(0, SIZE(events)-2) |
FOREACH (prec IN [events[n]] |
FOREACH (next IN [events[n+1]] |
MERGE (prec)-[:NEXT]->(next))))

View solution in original post

8 REPLIES 8

clem
Graph Steward

I'm not clear exactly what you want, but this might come in handy:


from

Hi clem,
Thx a lot for your reply.
In fact, I have the solution to create the relationships between all the Nodes:events linked to a single Node:topic. My problem is that I have thousands of different Nodes:topics and I don't know how to run this request through my entire graph.

I tried something like :
MATCH (tops:topic)
WITH tops
UNWIND tops AS top
MATCH (e:event)-[r:CONCERNS]-(t:topic {name: top.name})
WITH e ORDER BY e.dateEvent ASC
WITH COLLECT(e) AS events
FOREACH (n IN RANGE(0, SIZE(events)-2) |
FOREACH (prec IN [events[n]] |
FOREACH (next IN [events[n+1]] |
MERGE (prec)-[:NEXT]->(next))));

but it creates a relation between all the Nodes:event whatever they are linked to the same Nodes:topic or not

I don't know if you know this, but a Node can have 0 to any number of labels (node types).

So, you can create a Node with one or more specific labels, plus a general label.

Using Neo4J movie example:

CREATE (m:Movie:SciFi:Dystopian {name:"The Matrix"});
CREATE (m:Movie:SciFi:Western {name:"Cowboys and Aliens"});
CREATE (m:Movie:SciFi:Horror:Action {name:"Aliens"});
CREATE (m:Movie:Western {name:"High Noon"});

then you can do the query:
MATCH(m:Movie)-[]->(n) // for all movies
or
MATCH(m:SciFi)-[]->(n) // for only SciFi movies
or
MATCH(m:Western:SciFi)-[]->(n) // for movies that are in both genres

And it's not hard to add a new label to existing Nodes. This is one of the great features of Neo4J (which I don't think is emphasized enough). In the Object Oriented Programming world, the analogous feature is called "multiple inheritance". However, in the OOP world, multiple inheritance is somewhat problematic, whereas in Neo4J it's pretty simple.

I hope that helps. (I haven't quite wrapped my head around your problem, though.)

Thanks a lot for your answer.
I'm not a developer, I'm a beginner with Neo4j and not as good as I'd like in English, so I think my explanations we're not clear enough (anyway, the possibility to have multiple labels for the same Node could be very useful for other use cases).

As you can see in my first snapshot, I have "Events" connected to "Topics", and I would like to create all the "NEXT" relationships between the "Events" with a single Cypher command.

The final result should be like the following snapshot :

.

Any idea ?

Your latest picture is more helpful!

I'm new to Neo4J too, but I have experience with programming.

You should look at Neo4J's Scalar Functions and aggregating functions which are building blocks.

I think these two scalar functions could help:

and
https://neo4j.com/docs/cypher-manual/current/functions/aggregating/#functions-collect to covert nodes into a list.

I would try something like:
Make the lists of the connect events; get the head and tail of each list; connect the heads and tails.

You might be able to make a query to get all the Events that have no prior events (the head) and all the Events that have no next events (the tail) and glue those together. Then drop the first event from the list without a prior and the last event from the list without a next.

You can use ORDER BY to get the dates in order.

Being a newbie with Neo4J I sort of know what to do but not exactly....

I hope that helps.

Try this:

Step 1: Export the topic to a csv file:

CALL apoc.export.csv.query("
MATCH (tops:topic)
with distinct id(tops) as ID, tops.name as topic
RETURN ID, topc", "topics.csv", {})

This csv file will be in 'import' folder.

Step 2: Use LOAD CSV

LOAD CSV WITH HEADERS FROM "file:///topics.csv" AS row
WITH row

MATCH (t:topic) where id(t) = toInteger(row.ID)

MATCH (e:event)-[r:CONCERNS]-(t)
WITH e ORDER BY e.dateEvent ASC
WITH COLLECT(e) AS events
FOREACH (n IN RANGE(0, SIZE(events)-2) |
FOREACH (prec IN [events[n]] |
FOREACH (next IN [events[n+1]] |
MERGE (prec)-[:NEXT]->(next))))

Hi,

First of all thanks a lot for your time and your ideas.
Finally, I found the solution based on your proposal.

The final cypher request to solve my problem is the following

MATCH (top:topic)
CALL
{
WITH top
MATCH (e:event)-[r:CONCERNS]-(t:topic {name: top.name})
WITH e ORDER BY e.dateEvent ASC
WITH COLLECT(e) AS events
FOREACH (n IN RANGE(0, SIZE(events)-2) |
FOREACH (prec IN [events[n]] |
FOREACH (next IN [events[n+1]] |
MERGE (prec)-[:NEXT]->(next))))
Return events
}
return top.name;

It seems so simple at the end !

Again, thanks a lot and have a good day

Thanks for your appreciation!