Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.
12-23-2020 02:12 AM
Hello,
I am interesting to use graph DB in Intelligent Transportation Systems. I need to represent entities (nodes) and relations (edges) as well as their changes over time. So, node or edge will be represented with time. When I want to update node or edge, the old one will be archived and the new one will take place. So, updates are not destructive. Later, I can ask for a situation in a specific time.
Is this possible with Neo4j.
12-23-2020 11:32 AM
Hi @achraf.makni, yes it is possible. Neo4j support Temporal datatypes.
You can query max(timestamp) and get the latest record.
But I do have some questions -> If a node has already like 10 relationship, and when you update that node, I believe you want create a new node, along with all the 10 relationships. I believe this will create a overhead on the number of nodes and relationships.
What use case are you trying to solve ? Let me see if there is a better design approach.
12-23-2020 12:38 PM
I had an interesting time researching this. Originally, I had thought that you can create multiple labels for a Relationship or Remove a label from a relationship, but it appears that in Neo4J, every Relationship MUST have one and only one Label.
So, the trick is to make archived Relationships different from current ones
I can think of two ways of doing this.
First way is to add a property on a Relationship to indicate whether it is archived or not. I think that may have performance issues. In addition, it might be harder to hide the archived relationships. (I think Bloom can do this better than the Browser.)
Second way, is to rename the Relationship Label. You need APOC call to do this:
As an example, using the movie DB:
MATCH(p:Person {name:"Ed Harris"})-[r:ACTED_IN]->(m:Movie)
WITH collect(r) as rels, // need a list of relationships
p as p, m as m // need this to be able to return p and m
call apoc.refactor.rename.type("ACTED_IN", "EMOTED_IN", rels). // "type" means relationship label
YIELD committedOperations // number of renames done
return p, m
I believe Bloom can better hide the archived relationships but the Browser will show all relationships whether you want them or not. Unfortunately, you need an Enterprise license to use Bloom.
12-23-2020 06:38 PM
Hi @achraf.makni,
I have created a sample code to illustrate your archival process. I have taken an example of a truck at various cities with a date and current property set to True.
Note this is a very simple demo I have created.
// create an empty database
match (n) detach delete (n);
//Create a truck
merge (n:Truck{truck_id:1}) ;
//Create an initial city
merge (l:Location{name:"Austin"});
//Create an initial relationship
match (n:Truck{truck_id:1}), (l:Location{name:"Austin"})
merge (n)-[p:Position{date:date('2020-12-20'),current:True}]->(l);
//verify result
match (t:Truck{truck_id:1})-[r:Position]->(l:Location)
return t.truck_id,r.date,r.current,l.name;
╒════════════╤════════════╤═══════════╤════════╕
│"t.truck_id"│"r.date" │"r.current"│"l.name"│
╞════════════╪════════════╪═══════════╪════════╡
│1 │"2020-12-20"│true │"Austin"│
└────────────┴────────────┴───────────┴────────┘
//Add a new city, with date, with current status
match (t:Truck{truck_id:1})-[r:Position]->(l:Location)
with max(r.date) as max_date,t,l
match (t)-[r]->(l)
where r.date=max_date
set r.current=False
with t
merge (l:Location{name:"Houston"})
merge (t)-[r:Position{date:date('2020-12-21'),current:True}]->(l)
return distinct t.truck_id,r.date,r.current,l.name ;
╒════════════╤════════════╤═══════════╤═════════╕
│"t.truck_id"│"r.date" │"r.current"│"l.name" │
╞════════════╪════════════╪═══════════╪═════════╡
│1 │"2020-12-21"│true │"Houston"│
└────────────┴────────────┴───────────┴─────────┘
//Verify
match (t:Truck{truck_id:1})-[r:Position]->(l:Location)
return t.truck_id,r.date,r.current,l.name
╒════════════╤════════════╤═══════════╤═════════╕
│"t.truck_id"│"r.date" │"r.current"│"l.name" │
╞════════════╪════════════╪═══════════╪═════════╡
│1 │"2020-12-21"│true │"Houston"│
├────────────┼────────────┼───────────┼─────────┤
│1 │"2020-12-20"│false │"Austin" │
└────────────┴────────────┴───────────┴─────────┘
//Add another city
match (t:Truck{truck_id:1})-[r:Position]->(l:Location)
with max(r.date) as max_date,t,l
match (t)-[r]->(l)
where r.date=max_date
set r.current=False
with t
merge (l:Location{name:"Dallas"})
merge (t)-[r:Position{date:date('2020-12-22'),current:True}]->(l)
return distinct t.truck_id,r.date,r.current,l.name ;
//Result-
╒════════════╤════════════╤═══════════╤════════╕
│"t.truck_id"│"r.date" │"r.current"│"l.name"│
╞════════════╪════════════╪═══════════╪════════╡
│1 │"2020-12-22"│true │"Dallas"│
└────────────┴────────────┴───────────┴────────┘
//Verify
match (t:Truck{truck_id:1})-[r:Position]->(l:Location)
return t.truck_id,r.date,r.current,l.name
╒════════════╤════════════╤═══════════╤═════════╕
│"t.truck_id"│"r.date" │"r.current"│"l.name" │
╞════════════╪════════════╪═══════════╪═════════╡
│1 │"2020-12-22"│true │"Dallas" │
├────────────┼────────────┼───────────┼─────────┤
│1 │"2020-12-21"│false │"Houston"│
├────────────┼────────────┼───────────┼─────────┤
│1 │"2020-12-20"│false │"Austin" │
└────────────┴────────────┴───────────┴─────────┘
//Query the latest date
match (t:Truck)-[r:Position]->(l:Location)
with max(r.date) as max_date
match (t)-[r:Position{date:max_date}]->(l)
return t as truck_id,r as date_status,l as location_name;
╒══════════════╤════════════════════════════════════╤═════════════════╕
│"truck_id" │"date_status" │"location_name" │
╞══════════════╪════════════════════════════════════╪═════════════════╡
│{"truck_id":1}│{"date":"2020-12-22","current":true}│{"name":"Dallas"}│
└──────────────┴────────────────────────────────────┴─────────────────┘
Things to improve -
With your limited use case, this is the demo I have come up with. If you need more details, please, feel free to contact me.
All the sessions of the conference are now available online