TuringDB home pagelight logodark logo
  • Discord
  • GitHub
  • Website
TuringDB

Get Started

  • Introduction
  • Get Started
  • Claude Code Skill
  • Commands

Concepts

  • Overview
  • A Columnar Graph Database
  • Versioning System
  • The DataPart System
  • Zero-Locking Architecture
  • Snapshots Isolation

Benchmarks

  • Results Summary
  • Technical Report

Query Language

  • Overview
  • Matching
  • Paths
  • Results and Aggregation
  • Subqueries
  • Functions and Types
  • Writing Data
  • Procedures and Commands
  • CheatSheet

Importing data

  • JSONL
  • CSV
  • Neo4j
  • GML
  • Parquet

Graph Development

  • Create Graph
  • Load Graph
  • Load External data
  • Create a Change
  • List Changes
  • Create Nodes and Edges
  • Update Properties
  • Submit a Change
  • Time Travel
  • Graph Examples

Vector Search

  • Vector Search

Graph Algorithms

  • Shortest Path

Tutorials

  • Example Notebooks

Python SDK

  • Get Started
  • Reference

Troubleshooting

  • Troubleshooting

  • Variable-length paths
  • Quantified path patterns
  • Named paths
  • Finding routes
Query Language

Paths

Variable-length paths, quantified path patterns and named paths in TuringDB.

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:

SyntaxHops
-[: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 DISTINCT or 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] and UNWIND e work on it. To read edge properties along a path, name the path and use relationships(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.name

The 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 hops
  • nodes(p) and relationships(p) return lists of IDs. Read properties through a list comprehension.
  • length(p) is the number of hops.
  • A bare RETURN p comes back as a list of {"type": "node" | "edge", "id": ...} dictionaries.
  • count(p) counts paths.
  • OPTIONAL MATCH p = ... RETURN p IS NULL works.

​
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 1

To sum a property along a route, compute the list with a comprehension first, as above.

For a true weighted shortest path, see Shortest path.

MatchingResults and Aggregation
githublinkedinyoutubediscord