Solve Problems Virtually in Neo4j
In this blog, we will present the solution for real-world scenarios virtually using a Neo4j graph.
Many times, we developers come across scenarios where we try to show the graph in such a way that it hides all the intermediate nodes/relationships in the model, revealing the abstracted information relevant to business users (without using any visualization tool), without modifying the graph model.
To be precise, this means showing the direct relationship between any two nodes based on the intermediate patterns (which may not need to be exposed).
The answer is hidden in the Neo4j APOC library. It has the capability to virtually project nodes and relationships.
First, let’s ingest some sample data:
MERGE(n:Traveller{name:'JustAnotherTraveller'})
MERGE(a:Place{place:'Munnar'})
MERGE(b:Place{place:'Himalayas'})
MERGE(c:Place{place:'Mount Abu'})
MERGE(d:Place{place:'Mount Everest'})
MERGE(n)-[:TRAVELLED{travelDate:DATE('2021–10–10')}]->(a)
MERGE(n)-[:TRAVELLED{travelDate:DATE('2021–12–11')}]->(b)
MERGE(n)-[:TRAVELLED{travelDate:DATE('2022–02–10')}]->(c)
MERGE(n)-[:TRAVELLED{travelDate:DATE('2021–05–20')}]->(d)
Real problem statement:
In this blog, we will show the timeline journey of any given traveler in the database (in this case, a traveler with the name ‘JustAnotherTraveler’). How can we do that without modifying the model?
Below is the Cypher code snippet to output the entire journey of the traveler.
The general syntax for the function is:
apoc.create.vRelationship(startNode,'REL_TYPE', {key:value,…},endNode)
WITH 'JustAnotherTraveller' as travellerName
MATCH (t:Traveller{name:travellerName})-[r:TRAVELLED]->(p:Place)WITH t,p,r.travelDate as travelDate
ORDER BY r.travelDate
WITH t, collect([p,travelDate]) as journeysWITH t,journeyList,size(journeys) as lRETURN t,
[x IN range(0,l-1)|journeys[x][0]],
apoc.create.vRelationship(t,'TRAVELLED_TO',
{travelledOn:journeys[0][1]},journeys[0][0]),
[x IN range(0,l-2)|
apoc.create.vRelationship(journeys[x][0],'TRAVELLED_TO',
{travelledOn:journeys[x+1][1]},journeys[x+1][0])]
WITH ‘JustAnotherTraveler’ as travelerName
— we can parameterize the traveler name.
In the Return statement, we are returning all the nodes from the collect list journeys
using range [x IN range(0,l-1)|journeys[x][0]]
and then creating virtual relationship at each level using another range [x IN range(0,l-2)|apoc.create.vRelationship(journeyList[x][0],’TRAVELLED_TO’,{travelledOn:journeys[x+1][1]},journeys[x+1][0])]
.
The best part is that it’s generalized for any traveler present in your database. All we need to do is run this query and his/her entire journey will be on our screen. Also, we can use this Cypher as a source query to render the virtual graph on the visualization tool as well (if it supports Cypher graph results).
The virtual concept is actually being used as a popular feature in many of the graph visualization tools like Bloom, Hume etc., which actually helps developers answer certain business problems keeping graph abstraction in place.
You can reach out to me on my Linkedin profile for any discussions/ideas on Neo4j or graph use cases!