Overview
A quantified path pattern defines a variable-length path by repeating the entire path or a segment a specified number of times. A quantified path pattern can be formed by affixing a quantifier to either an edge pattern or a parenthesized path pattern, creating quantified edges or quantified paths.
<quantified path pattern> ::=
<quantified edges> | <quantified paths>
<quantified edges> ::=
<edge pattern> <quantifier>
<quantified paths> ::=
<parenthesized path pattern> <quantifier>
Quantifiers
A quantifier is written as postfix on either an edge pattern or a parenthesized path pattern.
Quantifier |
Description |
---|---|
{m,n} |
Between m and n repetitions |
{m} |
Exactly m repetitions |
{m,} |
m or more repetitions |
{,n} |
Between 0 and n repetitions |
* |
Between 0 and more repetitions |
+ |
Between 1 and more repetitions |
When the repetition of 0
is indicated, a path (or subpath) with zero edges that only contains the initial node will be included in the matchings.
Quantified Edges
Quantified edges are built by an edge pattern followed by a quantifier that specifies how many times the edge repeats. Note that the quantifier can be applied to both full and abbreviated edge patterns.

This path pattern expression is equivalent to:

The repeated edges are implicitly connected by empty node patterns.
Example Graph

CREATE GRAPH myGraph {
NODE User ({name string}),
NODE Movie ({name string}),
EDGE Follows ()-[{}]->(),
EDGE Likes ()-[{}]->()
} PARTITION BY HASH(Crc32) SHARDS [1]
INSERT (purplechalk:User {_id: "U01", name: "purplechalk"}),
(mochaeach:User {_id: "U02", name: "mochaeach"}),
(rowlock:User {_id: "U03", name: "rowlock"}),
(quasar92:User {_id: "U04", name: "Quasar92"}),
(velvet:User {_id: "U05", name: "Velvet"}),
(brainy:User {_id: "U06", name: "Brainy"}),
(quickfox:User {_id: "U07", name: "Quickfox"}),
(inception:Movie {_id: "M01", name: "Inception"}),
(purplechalk)-[:Follows]->(mochaeach),
(mochaeach)-[:Follows]->(rowlock),
(rowlock)-[:Follows]->(quasar92),
(quasar92)-[:Follows]->(velvet),
(brainy)-[:Follows]->(mochaeach),
(mochaeach)-[:Likes]->(inception),
(quickfox)-[:Likes]->(inception)
Fixed Lowerbound and Upperbound
Gets users who Brainy
can reach by 1 to 3 outgoing Follows
edges:
MATCH (:User {name: 'Brainy'})-[:Follows]->{1,3}(u:User)
RETURN collect_list(u.name) AS names
Result:
names |
---|
["mochaeach", "rowlock", "Quasar92"] |
Fixed Length
Gets users who Brainy
can reach by exact 2 outgoing Follows
edges:
MATCH (:User {name: 'Brainy'})-[:Follows]->{2}(u:User)
RETURN collect_list(u.name) AS names
Result:
names |
---|
["rowlock"] |
Fixed Lowerbound
Gets users who Brainy
can reach by 2 or more Follows
edges:
MATCH (:User {name: 'Brainy'})-[:Follows]-{2,}(u:User)
RETURN collect_list(u.name) AS names
Result:
names |
---|
["rowlock", "purplechalk", "Quasar92", "Velvet"] |
Gets users who Brainy
can reach by 0 or more outgoing Follows
edges:
MATCH (:User {name: 'Brainy'})-[:Follows]->*(u:User)
RETURN collect_list(u.name) AS names
Result:
names |
---|
["Brainy", "mochaeach", "rowlock", "Quasar92", "Velvet"] |
Gets users who Brainy
can reach by 1 or more outgoing Follows
edges:
MATCH (:User {name: 'Brainy'})-[:Follows]->+(u:User)
RETURN collect_list(u.name) AS names
Result:
names |
---|
["mochaeach", "rowlock", "Quasar92", "Velvet"] |
Fixed Upperbound
Gets users who Brainy
can reach by 0 to 2 Follows
edges:
MATCH (:User {name: 'Brainy'})-[:Follows]-{,2}(u:User)
RETURN collect_list(u.name) AS names
Result:
names |
---|
["Brainy", "mochaeach", "rowlock", "purplechalk"] |
Quantified Abbreviated Edges
An abbreviated edge pattern applies no filtering on the label and property of edges. The following example gets users who Brainy
can reach by 1 to 2 edges:
MATCH (:User {name: 'Brainy'})-{1,2}(u:User)
RETURN collect_list(u.name) AS names
Result:
names |
---|
["mochaeach", "rowlock", "purplechalk", "QuickFox"] |
Quantified Paths
Quantified paths are built by an parenthesized path pattern followed by a quantifier that specifies how many times the path repeats.

This path term is equivalent to:

At the transition between groups, two node patterns are concatenated consecutively. They are combined to a single node pattern with all filtering conditions merged conjunctively. In this example, this is straightforward since the only filtering applied is the User
label:

With this, the above is simplified to:

Example Graph

CREATE GRAPH myGraph {
NODE User ({name string}),
NODE Device (),
EDGE Owns ()-[{}]->(),
EDGE Flows ()-[{packets int32}]->()
} PARTITION BY HASH(Crc32) SHARDS [1]
INSERT (jack:User {_id: "U01", name: "Jack"}),
(mike:User {_id: "U02", name: "Mike"}),
(c1:Device {_id: "Comp1"}),
(c2:Device {_id: "Comp2"}),
(c3:Device {_id: "Comp3"}),
(c4:Device {_id: "Comp4"}),
(jack)-[:Owns]->(c1),
(mike)-[:Owns]->(c4),
(c1)-[:Flows {packets: 20}]->(c2),
(c1)-[:Flows {packets: 30}]->(c4),
(c2)-[:Flows {packets: 34}]->(c3),
(c2)-[:Flows {packets: 12}]->(c4),
(c3)-[:Flows {packets: 74}]->(c4)
Fixed Lowerbound and Upperbound
Gets paths of 1 to 3 outgoing data flows from the device owned by Jack
to the device owned by Mike
, where each data flow has more than 15 packets:
MATCH p = (:User {name: 'Jack'})-[:Owns]->
((:Device)-[f:Flows WHERE f.packets > 15]->(:Device)){1,3}
<-[:Owns]-(:User {name: 'Mike'})
RETURN p
Result: p

Fixed Length
Gets paths of 3 outgoing data flows from the device owned by Jack
to the device owned by Mike
, where each data flow has more than 15 packets:
MATCH p = (:User {name: 'Jack'})-[:Owns]->
((:Device)-[f:Flows WHERE f.packets > 15]->(:Device)){3}
<-[:Owns]-(:User {name: 'Mike'})
RETURN p
Result: p

Fixed Lowerbound
Gets paths of 2 or more outgoing data flows from the device owned by Jack
to the device owned by Mike
, where each data flow has more than 15 packets:
MATCH p = (:User {name: 'Jack'})-[:Owns]->
((:Device)-[f:Flows WHERE f.packets > 15]->(:Device)){2,}
<-[:Owns]-(:User {name: 'Mike'})
RETURN p
Result: p

Gets paths of 0 or more outgoing data flows from the device owned by Jack
to the device owned by Mike
, where each data flow has more than 15 packets:
MATCH p = (:User {name: 'Jack'})-[:Owns]->
((:Device)-[f:Flows WHERE f.packets > 15]->(:Device))*
<-[:Owns]-(:User {name: 'Mike'})
RETURN p
Result: p

Gets paths of 1 or more outgoing data flows from the device owned by Jack
to the device owned by Mike
, where each data flow has more than 15 packets:
MATCH p = (:User {name: 'Jack'})-[:Owns]->
((:Device)-[f:Flows WHERE f.packets > 15]->(:Device))+
<-[:Owns]-(:User {name: 'Mike'})
RETURN p
Result: p

Fixed Upperbound
Gets paths of 0 to 2 outgoing data flows from the device owned by Jack
to the device owned by Mike
, where each data flow has more than 15 packets:
MATCH p = (:User {name: 'Jack'})-[:Owns]->
((:Device)-[f:Flows WHERE f.packets > 15]->(:Device)){,2}
<-[:Owns]-(:User {name: 'Mike'})
RETURN p
Result: p

Degree of Reference of Element Variables
If an element variable is declared in a quantified path pattern, it may bind to multiple graph elements. References to the element variable are interpreted contextually.
Example Graph

CREATE GRAPH myGraph {
NODE User ({name string, age uint32}),
EDGE Follows ()-[{score uint32}]->()
} PARTITION BY HASH(Crc32) SHARDS [1]
INSERT (rowlock:User {_id: "U01", name: "rowlock", age: 24}),
(quasar92:User {_id: "U02", name: "Quasar92", age: 29}),
(claire:User {_id: "U03", name: "claire", age: 35}),
(rowlock)-[:Follows {score: 2}]->(quasar92),
(quasar92)-[:Follows {score: 3}]->(claire)
Singleton Degree of Reference
If the reference occurs inside the quantified path pattern, then the reference has singleton degree of reference and references at most one graph element.
MATCH p = ((a)-[]->(b) WHERE a.age < b.age){1,2}
RETURN p
Result: p

In this query, a
and b
are singletons that represent individual nodes. The condition a.age < b.age
is evaluated for each pair of nodes a
and b
as the path is matched.
Group Degree of Reference
If the reference occurs outside the quantified path pattern, then the reference has group degree of reference and references to the complete list of graph elements. In this circumstance, the element variable is viewed as a group variable.
MATCH p = ((a)-[]->(b)){1,2}
RETURN p, a, b
Result:
p | a | b |
---|---|---|
![]() |
[{"id":"U02","uuid":"4179342653223075841","schema":"User","values":{"name":"Quasar92","age":29}}] | [{"id":"U03","uuid":"12393908373546860546","schema":"User","values":{"name":"claire","age":35}}] |
![]() |
[{"id":"U01","uuid":"9223374235878031361","schema":"User","values":{"name":"rowlock","age":24}}] | [{"id":"U02","uuid":"4179342653223075841","schema":"User","values":{"name":"Quasar92","age":29}}] |
![]() |
[{"id":"U01","uuid":"9223374235878031361","schema":"User","values":{"name":"rowlock","age":24}},{"id":"U02","uuid":"4179342653223075841","schema":"User","values":{"name":"Quasar92","age":29}}] | [{"id":"U02","uuid":"4179342653223075841","schema":"User","values":{"name":"Quasar92","age":29}},{"id":"U03","uuid":"12393908373546860546","schema":"User","values":{"name":"claire","age":35}}] |
Variables a
and b
are exposed as group variables in the RETURN
statement. Each of them represents a list of nodes encountered along the matched paths, rather than a single node.
The following query throws syntax error since it treats a
and b
as singleton variables outside a quantified path pattern:
MATCH p = ((a)-[]->(b)){1,2}
WHERE a.age < b.age
RETURN p
The horizontal aggregation feature is not yet supported.
Group variables can be used to aggregate data along the quantified paths or edges, which is called the horizontal aggregation.
MATCH p = ()-[e]->{1,2}()
WHERE sum(e.score) > 2
RETURN p, collect_list(e.score) AS scores
Result:
p | scores |
---|---|
![]() |
[3] |
![]() |
[2,3] |