Path Queries¶
GQL supports variable-length paths for traversing the graph.
Variable-Length Patterns¶
-- One or more hops
MATCH (a:Person)-[:KNOWS*]->(b:Person)
RETURN a.name, b.name
-- Exactly 2 hops
MATCH (a:Person)-[:KNOWS*2]->(b:Person)
RETURN a.name, b.name
-- 1 to 3 hops
MATCH (a:Person)-[:KNOWS*1..3]->(b:Person)
RETURN a.name, b.name
-- 1 to 5 hops
MATCH (a:Person)-[:KNOWS*..5]->(b:Person)
RETURN a.name, b.name
-- At least 2 hops
MATCH (a:Person)-[:KNOWS*2..]->(b:Person)
RETURN a.name, b.name
Path Variables¶
-- Capture the path
MATCH path = (a:Person)-[:KNOWS*]->(b:Person)
WHERE a.name = 'Alix' AND b.name = 'Dave'
RETURN path
-- Path length
MATCH path = (a:Person)-[:KNOWS*]->(b:Person)
WHERE a.name = 'Alix'
RETURN b.name, length(path) AS distance
ORDER BY distance
A path variable holds the whole path of its pattern: over several edges, path runs from the first node through every edge and node to the last.
-- Three nodes and two edges per path
MATCH path = (a:Person)-[:KNOWS]->(b:Person)-[:WORKS_AT]->(c:Company)
RETURN [n IN nodes(path) | n.name] AS names, length(path) AS hops
Shortest Path¶
-- Find shortest path
MATCH path = shortestPath((a:Person)-[:KNOWS*]-(b:Person))
WHERE a.name = 'Alix' AND b.name = 'Dave'
RETURN path, length(path)
-- All shortest paths
MATCH path = allShortestPaths((a:Person)-[:KNOWS*]-(b:Person))
WHERE a.name = 'Alix' AND b.name = 'Dave'
RETURN path
Path Filtering¶
-- Filter paths by node properties
MATCH path = (a:Person)-[:KNOWS*]->(b:Person)
WHERE a.name = 'Alix'
AND all(n IN nodes(path) WHERE n.active = true)
RETURN path
-- Filter by relationship properties
MATCH path = (a:Person)-[:KNOWS*]->(b:Person)
WHERE a.name = 'Alix'
AND all(r IN relationships(path) WHERE r.strength > 0.5)
RETURN path
Path Functions¶
| Function | Description |
|---|---|
nodes(path) | List of nodes in path |
relationships(path) / edges(path) | List of edges in path |
length(path) | Number of edges in path |
isAcyclic(path) | True if no node appears more than once |
isSimple(path) | True if no node repeats except first = last |
isTrail(path) | True if no edge repeats |
ISO Path Quantifiers¶
The ISO standard uses curly-brace syntax as an alternative to *m..n. See Pattern Matching for the full comparison.
-- ISO: 2 to 4 hops
MATCH (a:Person)-[:KNOWS]->{2,4}(b:Person)
RETURN a.name, b.name
-- ISO: exactly 3 hops
MATCH (a:Person)-[:KNOWS]->{3}(b:Person)
RETURN a.name, b.name
Path Modes¶
Path modes restrict which traversals are valid. Place the mode keyword after the path variable, as below, or after MATCH for every pattern of the clause.
-- WALK (default): repeated nodes and edges allowed
MATCH path = WALK (a:Person)-[:KNOWS*]->(b:Person)
WHERE a.name = 'Alix'
RETURN b.name, length(path)
-- TRAIL: no edge can be visited more than once
MATCH path = TRAIL (a:Person)-[:KNOWS*]->(b:Person)
WHERE a.name = 'Alix'
RETURN b.name, length(path)
-- SIMPLE: no node visited more than once (except start = end)
MATCH path = SIMPLE (a:Person)-[:KNOWS*]->(b:Person)
WHERE a.name = 'Alix'
RETURN b.name, length(path)
-- ACYCLIC: strictly no repeated nodes
MATCH path = ACYCLIC (a:Person)-[:KNOWS*]->(b:Person)
WHERE a.name = 'Alix'
RETURN b.name, length(path)
Use path modes to control traversal behavior in cyclic graphs. ACYCLIC prevents infinite loops, while TRAIL allows revisiting nodes but not edges.
An unbounded WALK (-[:KNOWS*]->) returns every walk on a graph without a cycle, whatever its length. Around a cycle its walks never end: it fails once the path search reaches its memory budget, with an error that says to bound the quantifier or use TRAIL, ACYCLIC or ANY SHORTEST.
Path Mode Inside Parenthesized Patterns (G049)¶
Path modes can also be placed inside a parenthesized quantified pattern, overriding any outer mode:
-- TRAIL mode inside quantified pattern
MATCH (TRAIL (a)-[:KNOWS]->(b)){1,3}
RETURN DISTINCT b.name
-- ACYCLIC inside, with outer WALK
MATCH WALK (ACYCLIC (a)-[:KNOWS]->(b)){2,5}
RETURN a.name, b.name
WHERE Inside Parenthesized Patterns (G050)¶
A WHERE clause can filter within a parenthesized quantified pattern:
-- Only follow edges where the target meets a condition
MATCH ((a:Person)-[:KNOWS]->(b:Person) WHERE b.age > 30){1,3}
RETURN DISTINCT b.name
-- Combined with path mode
MATCH (TRAIL (a)-[e:KNOWS]->(b) WHERE e.since > 2020){1,4}
RETURN a.name, b.name
The WHERE holds for each step of the path, in every direction and path mode, also a condition on the step's nodes (a.x < b.x). The node patterns around the quantified pattern ((s)(...){1,3}(t)) and its own end nodes both hold, and + and * are accepted after a parenthesized pattern.
A parenthesized pattern of more than one edge repeats as a whole within its bounds: ((a)-[e1]->(m)-[e2]->(b)){1,3} matches 1 to 3 repetitions of the segment, its WHERE holds for each repetition, and outside the pattern e1 and e2 are the lists of their edges. Such a pattern needs an upper bound of at most 16 repetitions; without one, or with a larger one, it fails with an error.
Path Search Prefixes¶
Search prefixes control how many matching paths are returned, for each pair of endpoints: the paths of a pattern are grouped by their first and last node (for each row the pattern starts from), and each group keeps its own selection. See Pattern Matching for the complete list.
-- ANY SHORTEST: any one shortest path
MATCH path = ANY SHORTEST (a:Person)-[:KNOWS*]->(b:Person)
WHERE a.name = 'Alix' AND b.name = 'Dave'
RETURN path, length(path)
-- ALL SHORTEST: all paths of minimum length
MATCH path = ALL SHORTEST (a:Person)-[:KNOWS*]->(b:Person)
WHERE a.name = 'Alix' AND b.name = 'Dave'
RETURN path, length(path)
-- SHORTEST 3: the 3 shortest paths
MATCH path = SHORTEST 3 (a:Person)-[:KNOWS*]->(b:Person)
WHERE a.name = 'Alix' AND b.name = 'Dave'
RETURN path, length(path)
-- SHORTEST 2 GROUPS: every path of the 2 shortest lengths
MATCH path = SHORTEST 2 GROUPS (a:Person)-[:KNOWS*]->(b:Person)
WHERE a.name = 'Alix' AND b.name = 'Dave'
RETURN path, length(path)
-- ANY: one path to each person Alix reaches
MATCH path = ANY (a:Person {name: 'Alix'})-[:KNOWS*]->(b:Person)
RETURN b.name, length(path)
-- ANY SHORTEST TRAIL: the shortest path that takes no edge twice
MATCH path = ANY SHORTEST TRAIL (a:Person)-[:KNOWS]-{3,}(b:Person)
WHERE a.name = 'Alix' AND b.name = 'Dave'
RETURN path
The path mode of a search prefix restricts the paths it selects among: with a minimum of edges, the shortest walk may go back over an edge, which the shortest trail does not.
Shortest-path searches (these prefixes and shortestPath) only return paths that fit the edge's quantifier: ->+ or -[:KNOWS*]-> is one or more hops, ->{1,3} at most three, ->* also pairs a node with itself (length 0), and an edge without a quantifier is a single hop. A pair of nodes without such a path has no row; use OPTIONAL MATCH to keep it with a null path.
The path variable holds the path found, with nodes(path) and edges(path), and the variable of a quantified edge is the list of the path's edges. A property map or WHERE on the edge holds for every edge of the path: the search only takes such edges, so the shortest path is picked among the paths that meet it. A WHERE or FILTER after the pattern is checked on the path found instead. A search runs over one edge pattern between two node patterns.
-- The shortest route that takes roads only
MATCH path = ANY SHORTEST (a:City {name: 'Amsterdam'})-[r:ROUTE WHERE r.kind = 'road']->+(b:City {name: 'Prague'})
RETURN [n IN nodes(path) | n.name] AS stops, [x IN r | x.km] AS legs
Path Predicate Functions¶
Test structural properties of a captured path:
MATCH path = (a:Person)-[:KNOWS*]->(b:Person)
WHERE a.name = 'Alix'
RETURN
b.name,
length(path) AS hops,
isAcyclic(path) AS acyclic,
isSimple(path) AS simple,
isTrail(path) AS trail
-- Filter: only acyclic paths
MATCH path = (a:Person)-[:KNOWS*]->(b:Person)
WHERE a.name = 'Alix' AND isAcyclic(path)
RETURN b.name, length(path)
Paths as Values¶
Paths are first-class values in GQL (GV55). A path variable can be returned, compared and passed to functions:
-- Return the path itself
MATCH p = (a:Person {name: 'Alix'})-[:KNOWS]->(b:Person)
RETURN p
-- Path equality: two paths are equal if they traverse the same nodes and edges
MATCH p1 = (a:Person)-[:KNOWS]->(b:Person),
p2 = (c:Person)-[:KNOWS]->(d:Person)
WHERE a = c AND b = d
RETURN p1 = p2 AS same_path