These examples use the sample graph from the matching page.
Variable-length paths
TuringDB supports both its own postfix quantifiers and the Neo4j bracket form:
| Syntax | Hops |
|---|---|
-[:KNOWS]->+ | 1 or more |
-[:KNOWS]->* | 0 or more (includes the start node itself) |
-[:KNOWS]->{2,4}, {2}, {,3}, {2,} | between, exactly, up to, at least |
-[:KNOWS*1..3]->, -[:KNOWS*2]->, -[*..3]-, -[*0..1]-> | Neo4j style |
-[:KNOWS*]-> | 1 or more (unlike the postfix *) |
MATCH (a:Person {name: 'Alice'})-[:KNOWS]->+(b)
RETURN DISTINCT b.name
MATCH (a:Person {name: 'Alice'})-[:KNOWS*1..3]->(b)
RETURN DISTINCT b.name
MATCH (a)-[:KNOWS|WORKS_AT]->{1,2}(b)
RETURN a.name, b.name
MATCH (a)-[e:KNOWS WHERE e.since > 2012]->+(b)
RETURN a.name, b.name
MATCH (a)-[:KNOWS*1..3 {since: 2010}]->(b)
RETURN b.name
MATCH (a {name: 'Alice'})-[e:KNOWS]->+(b)
RETURN b.name, size(e)- Edge type alternatives (
[:KNOWS|WORKS_AT]) work on variable-length hops. - A predicate or property map applies to every hop.
-[e:KNOWS WHERE e.since > 2012]->+only follows edges that satisfy it, and-[:KNOWS*1..3 {since: 2010}]->requires every edge on the path to have that property value. - Trail semantics. Each edge is used at most once within a path, while nodes may repeat. Each distinct path is its own row, so use
DISTINCTor an aggregate to collapse them. - One quantifier per edge. Choose either
[*1..3]or{1,3}for an edge. - The edge variable of a variable-length hop is a list of edge IDs.
size(e),e[0],e[-1]andUNWIND ework on it. To read edge properties along a path, name the path and userelationships(p)(below).
Variable-length matching enumerates paths. On dense graphs the number of paths can grow very quickly, so always bound the length (*1..6 or {1,6}). For weighted shortest paths on large graphs, use the shortestPath statement.
Quantified path patterns
A quantified path pattern repeats a one-hop sub-pattern, with its own WHERE, a number of times:
MATCH (a:Person {name: 'Alice'}) ((x)-[r:KNOWS]->(y) WHERE r.since > 2009){1,3} (b)
RETURN b.name
MATCH (a:Person {name: 'Alice'}) ((x)-[:KNOWS]->(y) WHERE y.age > x.age)+ (b)
RETURN b.nameThe second query follows KNOWS edges only while ages strictly increase. Inside the parentheses only a single hop of the form (node)-[edge]->(node) [WHERE ...] is allowed, and the inner variables (x, r) become lists.
Named paths
Give a path a name to inspect its nodes and edges:
MATCH p = (a:Person {name: 'Alice'})-[:KNOWS]->+(b)
RETURN [n IN nodes(p) | n.name] AS names,
[r IN relationships(p) | r.since] AS sinces,
length(p) AS hops
ORDER BY hopsnodes(p)andrelationships(p)return lists of IDs. Read properties through a list comprehension.length(p)is the number of hops.- A bare
RETURN pcomes back as a list of{"type": "node" | "edge", "id": ...}dictionaries. count(p)counts paths.OPTIONAL MATCH p = ... RETURN p IS NULLworks.
Finding routes
For hop-count questions, undirected search, or when you need the properties along a route, combine variable-length paths with comprehensions:
// Fewest hops, returning the names along the route
MATCH p = (a:Person {name: 'Alice'})-[:KNOWS*1..6]->(b:Person {name: 'Dave'})
RETURN [n IN nodes(p) | n.name] AS route, length(p) AS hops
ORDER BY hops LIMIT 1
// k-hop neighbourhood and reachability
MATCH (a:Person {name: 'Alice'})-[:KNOWS]-{1,3}(b)
RETURN DISTINCT b.name
MATCH (a:Person {name: 'Alice'})-[:KNOWS]->+(b)
RETURN count(DISTINCT b)To sum a property along a route, build a list with a comprehension and aggregate over its elements:
MATCH p = (a:Person {name: 'Alice'})-[:KNOWS*1..6]->(b:Person {name: 'Dave'})
WITH [n IN nodes(p) | n.name] AS route, [r IN relationships(p) | r.since] AS years
UNWIND years AS y
WITH route, sum(y) AS total
RETURN route, total
ORDER BY total LIMIT 1To sum a property along a route, compute the list with a comprehension first, as above.
For a true weighted shortest path, see Shortest path.

