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} *..5 At most 5 hops
-- 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.

-- ANY: return any single matching path
MATCH ANY (a:Person)-[:KNOWS*]->(b:Person)
WHERE a.name = 'Alix' AND b.name = 'Dave'
RETURN a, b

-- ANY k: return up to k paths
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 = 'Dave'
RETURN a, b

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

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

-- SHORTEST k GROUPS: k groups of equal-length shortest paths
MATCH SHORTEST 2 GROUPS (a:Person)-[:KNOWS*]->(b:Person)
WHERE a.name = 'Alix' AND b.name = 'Dave'
RETURN a, b

Path Modes

Path modes restrict which paths are valid during traversal. Place the mode keyword before the pattern.

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

Match Modes

Match modes control uniqueness across multiple patterns in the same MATCH.

-- DIFFERENT EDGES: no edge can appear in more than one pattern binding
MATCH DIFFERENT EDGES
    (a)-[r1:KNOWS]->(b),
    (c)-[r2:KNOWS]->(d)
RETURN a.name, b.name, c.name, d.name

-- REPEATABLE ELEMENTS: relax the default uniqueness constraint
MATCH REPEATABLE ELEMENTS
    (a)-[:KNOWS]->(b),
    (a)-[:WORKS_WITH]->(b)
RETURN a.name, b.name