1
votes

I have Neo4j community 3.5.5, where I built a graph data model with rail station and line sections between stations. Stations and line sections are nodes and connect is the relationship linking them.

Stations and line sections

I would like to name a starting station and an ending station and sum up length of all rail section in between. I tried the Cypher query below but Neo4j does not recognize line_section as a node type.

match (n1:Station)-[:Connect]-(n2:Station)
where n1.Name='Station1' and n2.Name='Station3'
return sum(Line_Section.length)

I know it is possible to do the summing with Neo4j Traversal API. Is it possible to do this in Cypher?

2

2 Answers

2
votes

First capture the path from a start node to the end node in a variable, then reduce the length property over it.

MATCH path=(n1: Station { name: 'Station1' })-[:Connect]->(n2: Station { name: 'Station2' })
RETURN REDUCE (totalLength = 0, node in nodes(path) | totalLength + node.length) as totalDistance
1
votes

Assuming the line section nodes have the label Line_Section, you can use a variable-length relationship pattern to get the entire path, list comprehension to get a list of the line section nodes, UNWIND to get the individual nodes, and then use aggregation to SUM all the line section lengths:

MATCH p = (n1:Station)-[:Connect*]-(n2:Station)
WHERE n1.Name='Station1' AND n2.Name='Station3'
UNWIND [n IN NODES(p) WHERE 'Line_Section' in LABELS(n)] AS ls
RETURN p, SUM(ls.length) AS distance

Or, you could use REDUCE in place of UNWIND and SUM:

MATCH p = (n1:Station)-[:Connect*]-(n2:Station)
WHERE n1.Name='Station1' AND n2.Name='Station3'
RETURN p, REDUCE(s = 0, ls IN [n IN NODES(p) WHERE 'Line_Section' in LABELS(n)] |
  s + ls.length) AS distance

[UPDATED]

Note: a variable-length relationship with an unbounded number of hops is expensive, and can take a long time or run out of memory.

If you only want the distance for the shortest path, then this should be faster:

MATCH
  (n1:Station { name: 'Station1' }),
  (n2:Station {name: 'Station3' }),
  p = shortestPath((n1)-[*]-(n2))
WHERE ALL(r IN RELATIONSHIPS(p) WHERE TYPE(r) = 'Connect')
RETURN p, REDUCE(s = 0, ls IN [n IN NODES(p) WHERE 'Line_Section' in LABELS(n)] |
  s + ls.length) AS distance