Skip to content

Pattern Matching

Pattern matching is the core of GQL. This guide covers node and edge patterns in detail.

Node Patterns

-- Any node
(n)

-- Node with label
(p:Person)

-- Node with multiple labels
(e:Person:Employee)

-- Node with properties
(p:Person {name: 'Alix'})

-- Anonymous node (no variable)
(:Person)

Edge Patterns

-- Outgoing edge
(a)-[:KNOWS]->(b)

-- Incoming edge
(a)<-[:KNOWS]-(b)

-- Either direction
(a)-[:KNOWS]-(b)

-- Any edge type
(a)-[r]->(b)

-- Edge with properties
(a)-[:KNOWS {since: 2020}]->(b)

Complex Patterns

-- Chain of relationships
MATCH (a:Person)-[:KNOWS]->(b)-[:KNOWS]->(c)
RETURN a.name, b.name, c.name

-- Multiple patterns
MATCH (a:Person)-[:KNOWS]->(b), (a)-[:WORKS_AT]->(c)
RETURN a.name, b.name, c.name

-- Triangle pattern
MATCH (a)-[:KNOWS]->(b)-[:KNOWS]->(c)-[:KNOWS]->(a)
RETURN a.name, b.name, c.name

Path Alternation

Use | for set alternation (dedup) or |+| for multiset alternation (preserves duplicates):

-- Set alternation: match KNOWS or WORKS_WITH edges (dedup)
MATCH ((a)-[:KNOWS]->(b) | (a)-[:WORKS_WITH]->(b))
RETURN a.name, b.name

-- Multiset alternation: preserve duplicates across alternatives
MATCH ((a)-[:KNOWS]->(b) |+| (a)-[:KNOWS]->(b))
RETURN a.name, b.name

Multiple Relationship Types

-- Match any of multiple types
MATCH (a)-[:KNOWS|WORKS_WITH]->(b)
RETURN a.name, b.name

-- Match with type variable
MATCH (a)-[r:KNOWS|WORKS_WITH]->(b)
RETURN a.name, type(r), b.name

Optional Patterns

-- Return results even if pattern doesn't match
MATCH (p:Person)
OPTIONAL MATCH (p)-[:HAS_PET]->(pet)
RETURN p.name, pet.name

Element WHERE Clauses

Filter directly inside a pattern element, without a separate WHERE clause:

-- Node-level WHERE
MATCH (p:Person WHERE p.age > 30)
RETURN p.name

-- Edge-level WHERE
MATCH (a)-[r:KNOWS WHERE r.since >= 2020]->(b)
RETURN a.name, b.name, r.since

Label Expressions

GQL supports rich label expressions using the IS keyword with boolean operators.

-- Single label
MATCH (n IS Person) RETURN n.name

-- Disjunction: match Person OR Company
MATCH (n IS Person | Company) RETURN n.name

-- Conjunction: match nodes with BOTH labels
MATCH (n IS Person & Employee) RETURN n.name

-- Negation: match anything except Inactive
MATCH (n IS !Inactive) RETURN n.name

-- Wildcard: match any label
MATCH (n IS %) RETURN n.name

-- Parenthesized combinations
MATCH (n IS (Person | Company) & !Inactive) RETURN n.name

Simplified Path Patterns

The ISO standard provides a shorthand syntax using / delimiters instead of brackets:

-- Outgoing: -/:Label/-> is equivalent to -[:Label]->
MATCH (a:Person)-/:KNOWS/->(b:Person)
RETURN b.name

-- Incoming: <-/:Label/- is equivalent to <-[:Label]-
MATCH (b:Person)<-/:KNOWS/-(a:Person)
RETURN a.name

-- Undirected: -/:Label/- is equivalent to -[:Label]-
MATCH (a:Person)-/:KNOWS/-(b:Person)
RETURN b.name

-- Multiple label alternatives: -/:L1|L2/->
MATCH (a:Person)-/:KNOWS|WORKS_WITH/->(b)
RETURN b.name

-- Tilde form: ~/:Label/~
MATCH (a:Person)~/:KNOWS/~(b:Person)
RETURN b.name

ISO Tilde Syntax (Undirected Edges)

The ISO standard uses tilde (~) for undirected edges, as an alternative to the Cypher-style -[]-:

-- ISO undirected edge
MATCH (a)~[r:KNOWS]~(b)
RETURN a.name, b.name

-- Equivalent Cypher-style
MATCH (a)-[r:KNOWS]-(b)
RETURN a.name, b.name

ISO Path Quantifiers

The ISO standard uses curly-brace syntax {m,n} for path quantifiers, as an alternative to the Cypher-style *m..n:

ISO Syntax Cypher Syntax Meaning
{2,5} *2..5 2 to 5 hops
{3} *3 Exactly 3 hops
{2,} *2.. At least 2 hops
{,5} *0..5 0 to 5 hops

An omitted lower bound is 0 in the ISO syntax ({,5} also matches the start node itself, with no edge), and 1 in the Cypher syntax (*..5 is 1 to 5 hops), as each standard defines it. A quantifier whose upper bound is below its lower bound ({3,1}, *3..1 or *..0) is a syntax error in GQL, and so is an edge with a quantifier both inside and after its brackets (-[:KNOWS*1..2]->{2}). In Cypher, *3..1 is an empty range, which matches no path, as openCypher defines it.

-- ISO: exactly 2 hops
MATCH (a:Person)-[:KNOWS]->{2}(b:Person)
RETURN a.name, b.name

-- ISO: 1 to 3 hops
MATCH (a:Person)-[:KNOWS]->{1,3}(b:Person)
RETURN a.name, b.name

-- Cypher equivalent: 1 to 3 hops
MATCH (a:Person)-[:KNOWS*1..3]->(b:Person)
RETURN a.name, b.name

Questioned Edge

The questioned edge ->? matches 0 or 1 hops, making the relationship optional. If the edge exists, it is matched; if not, the target node is null.

-- Optional relationship (0 or 1 hops)
MATCH (p:Person)-[:MANAGES]->?(team:Team)
RETURN p.name, team.name

Path Search Prefixes

Path search prefixes control how many matching paths are returned. They select per 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.

-- ANY: one path for each pair of endpoints
MATCH ANY (a:Person)-[:KNOWS*]->(b:Person)
WHERE a.name = 'Alix'
RETURN b.name

-- ANY k: up to k paths for each pair
MATCH ANY 3 (a:Person)-[:KNOWS*]->(b:Person)
WHERE a.name = 'Alix'
RETURN b.name

-- ALL SHORTEST: all paths of minimum length
MATCH ALL SHORTEST (a:Person)-[:KNOWS*]->(b:Person)
WHERE a.name = 'Alix' AND b.name = 'Mia'
RETURN a, b

-- ANY SHORTEST: any one shortest path
MATCH ANY SHORTEST (a:Person)-[:KNOWS*]->(b:Person)
WHERE a.name = 'Alix' AND b.name = 'Mia'
RETURN a, b

-- SHORTEST k: the k shortest paths
MATCH SHORTEST 3 (a:Person)-[:KNOWS*]->(b:Person)
WHERE a.name = 'Alix' AND b.name = 'Mia'
RETURN a, b

-- SHORTEST k GROUPS: every path of the k shortest lengths
MATCH SHORTEST 2 GROUPS (a:Person)-[:KNOWS*]->(b:Person)
WHERE a.name = 'Alix' AND b.name = 'Mia'
RETURN a, b

Which paths ANY keeps is up to the implementation: Grafeo keeps the shortest ones. A prefix can carry a path mode, which restricts the paths it selects among, and PATH or PATHS may follow it:

-- The shortest trail: no edge twice, even when a walk back would be shorter
MATCH p = ANY SHORTEST TRAIL (a:Person)-[:KNOWS]-{2,}(b:Person)
WHERE a.name = 'Jules' AND b.name = 'Mia'
RETURN length(p)

-- Two acyclic paths to each node
MATCH p = ANY 2 ACYCLIC PATHS (a:Person {name: 'Alix'})-[:KNOWS]-{1,4}(b)
RETURN b.name, length(p)

A prefix after the path variable (p = ANY SHORTEST (...)), or before a later pattern of the MATCH, holds for that pattern; one right after MATCH holds for every pattern of the clause without its own. The conditions of the edge pattern (its property map and WHERE) hold for every edge before the selection, while a WHERE after the pattern is checked on the paths selected. A selective search runs over one edge pattern between two node patterns.

Path Modes

Path modes restrict which paths are valid during traversal. Place the mode keyword after MATCH for every pattern of the clause, or after the path variable for one pattern (MATCH p = TRAIL (...)).

Mode Rule
WALK Default. Repeated nodes and edges allowed
TRAIL No repeated edges
SIMPLE No repeated nodes (except start = end)
ACYCLIC No repeated nodes at all
-- WALK (default): allow cycles
MATCH WALK (a:Person)-[:KNOWS*]->(b:Person)
WHERE a.name = 'Alix'
RETURN b.name

-- TRAIL: each edge visited at most once
MATCH TRAIL (a:Person)-[:KNOWS*]->(b:Person)
WHERE a.name = 'Alix'
RETURN b.name

-- SIMPLE: each node visited at most once (except endpoints)
MATCH SIMPLE (a:Person)-[:KNOWS*]->(b:Person)
WHERE a.name = 'Alix'
RETURN b.name

-- ACYCLIC: strictly no repeated nodes
MATCH ACYCLIC (a:Person)-[:KNOWS*]->(b:Person)
WHERE a.name = 'Alix'
RETURN b.name

A path mode holds for the whole path of a pattern, over all of its edges: MATCH TRAIL (a)-[:KNOWS]-(b)-[:KNOWS]-(c) never goes back over the edge it came on.

Match Modes

Match modes control whether the edges of a MATCH may repeat, across all of its patterns.

-- DIFFERENT EDGES: no edge is bound twice, by any two edge patterns of the MATCH
-- (named or not, and every edge of a quantified one)
MATCH DIFFERENT EDGES
    (a)-[r1:KNOWS]->(b),
    (c)-[r2:KNOWS]->(d)
RETURN a.name, b.name, c.name, d.name

-- REPEATABLE ELEMENTS (the default): edges and nodes may repeat
MATCH REPEATABLE ELEMENTS
    (a)-[:KNOWS]->(b),
    (a)-[:WORKS_WITH]->(b)
RETURN a.name, b.name

A match mode and a path mode combine: MATCH DIFFERENT EDGES ACYCLIC (a)-[:KNOWS]-(b)-[:KNOWS]-(c). KEEP DIFFERENT EDGES after a pattern asks the same of the edges of that one pattern.