Metropolitan Transport Network from São Paulo, Brazil, mapped in a NoSQL graph database.
Read this in other languages: Português
You can read a more detailed explanation (in portuguese) in my medium: https://medium.com/@igorrozani/transporte-de-sp-em-um-banco-de-grafos-3ce17d4f1f41
Based in the metropolitan transport network map from São Paulo (image below), i mapped all the stations, terminals, lines and connections utilizing the database Neo4j and the language openCypher.
It was defined the following database model:
The nodes are:
- BusTerminal - bus terminals. Example: São Bernardo;
- Company - the company responsable by the transport line. Example: CPTM;
- Line - the transport lines. Example: Yellow line;
- MetroStation - the metro stations. Example: Paulista;
- OrcaShuttleTerminal - Orca Shuttle terminals. Example: Jabaquara;
- PointOfInterest - points of interest from the map. Example: Zoo;
- TouristicTerminal - tourist terminal stations. Example: Paranapiacaba;
- TrainStation - train stations. Example: Morumbi.
And the relationships are:
- CONNECT - connection between stations and/or terminals;
- HAS - relationship between Station/Terminal and the PointOfInterest;
- INTEGRATION - integration between different types of stations and terminals;
- OWN - relationship between the company and line, to represent that the company owns that line;
- PART_OF - relationship between the station/terminal and line, to represent that the station/terminal is part of that line.
To run this project, it's necessary to install the Neo4j, you can download it here.
CREATE (:Line {name:'Emerald', number:9})
MATCH (s1:TrainStation{name:'Poá'}),(s2:TrainStation{name:'Suzano'})
CREATE (s1)-[r:CONNECT{transport: 'train'}]->(s2)
MATCH (n)-[r]-()
DELETE n,r
MATCH (n)
RETURN n
MATCH (l:Line)-[:PART_OF]-(s)
RETURN l.name AS Line, collect(s.name) AS Stations
MATCH (s {hasElevator:true})
RETURN s
MATCH ({name:'Luz'})-[:CONNECT]-(s)
Return s
MATCH (s:TouristicTerminal)-[:CONNECT]-({name:'Luz'})
Return s
MATCH (c:Company)-[:OWN]-(l:Line)
WITH c, l
ORDER BY l.number, l.name
WITH c, collect(CASE WHEN l.number IS NULL THEN l.name ELSE l.number + ' - ' + l.name END) as lines
RETURN c.name, lines
ORDER BY c.name
MATCH ()-[r]-()
WITH DISTINCT type(r) AS relationships
RETURN DISTINCT relationships
ORDER BY relationships
MATCH (n)
WITH DISTINCT labels(n) AS labels
UNWIND labels AS label
RETURN DISTINCT label
ORDER BY label
MATCH (l:Line)-[:PART_OF]-(s)
WITH l, count(s) as qtd
RETURN l.name, qtd
ORDER BY l.name
MATCH (n)
WHERE n.hasBikeAttachingPost = true OR n.hasBikeParkingTerminal = true
RETURN n
MATCH (:Line)-[p:PART_OF]-(s)
WITH s, count(p) as qtd
WHERE qtd > 1
RETURN s.name, qtd
ORDER BY qtd DESC
MATCH x = shortestPath((s1{name:"Grajaú"})-[:CONNECT*]-(s2{name:"Rio Grande da Serra"}))
RETURN EXTRACT(n IN NODES(x) | n.name) AS Directions
MATCH
(s1{name:"Grajaú"}),
(s2{name:"Rio Grande da Serra"}),
p = shortestPath((s1)-[:CONNECT*]-(s2))
WHERE ALL (x IN RELATIONSHIPS(p) WHERE x.transport='train' OR x.transport='metro')
RETURN p