# COLLECT_LIST
Source: https://gql.ch/docs/functions/collect-list
COLLECT_LIST function collects values into a list
Collects values into a list
### Calculating Geometric Mean using COLLECT\_LIST and REDUCE
Geometric Mean is a measure of central tendency that calculates an average of the data using multiplication instead of addition. For a set of n numbers, the geometric mean is the nth root of the product of those numbers. For example, the geometric mean of the numbers 2, 3, and 14 equals (2 \* 3 \* 14)1/3 = (84)1/3 = 4.37952. Geometric Mean is particularly useful when the data is skewed and a simple average does not work.
Suppose we are interested in the Geometric Mean Income of all the people who live in the same city as Fatima:
```mermaid theme={null}
%%{init: {'theme':'base', 'themeVariables': {'lineColor':'#F1FA8C','secondaryColor':'#F1FA8C','background':'#282A36'}}}%%
graph LR
subgraph row1[" "]
saqib[:person
name: Saqib๐จ
income: 375000]
scott[:person
name: Scott ๐จ
income: 205000]
fatima[:person
name: Fatima ๐ฉ
income: 195000]
hannah[:person
name: Hannah ๐ฉ
income: 185000]
zainab[:person
name: Zainab ๐ฉ
income: 190000]
capitola[:city
name:Capitola]
end
subgraph row2[" "]
eleni[:person
name: Eleni ๐ฉ
income: 185000]
uroosa[:person
name: Uroosa ๐ฉ
income: 175000]
angela[:person
name: Angela ๐ฉ
income: 195000]
maryam[:person
name: Maryam ๐ฉ
income: 155000]
santacruz[:city
name:Santa Cruz]
end
subgraph row3[" "]
laila[:person
name: Laila ๐ฉ
income: 180000]
huda[:person
name: Huda ๐ฉ
income: 172000]
end
%% saqib -->|:relationship
type: co-worker| fatima
%% fatima -->|:relationship
type: friend| eleni
%% eleni -->|:relationship
type: friend| uroosa
%% saqib -->|:relationship
type: friend| angela
%% angela -->|:relationship
type: co-worker| scott
%% scott -->|:relationship
type: friend| uroosa
saqib -->|:lives_in| capitola
scott -->|:lives_in| capitola
fatima -->|:lives_in| capitola
hannah -->|:lives_in| capitola
zainab -->|:lives_in| capitola
angela -->|:lives_in| santacruz
uroosa -->|:lives_in| santacruz
eleni -->|:lives_in| santacruz
maryam -->|:lives_in| santacruz
classDef nodes fill:#BD93F9,stroke-width:0px
class saqib,fatima,angela,uroosa,eleni,scott,maryam,zainab,hannah,huda,laila nodes
classDef subgraphStyle fill:#282A36, stroke-width:0px
class row1,row2,row3 subgraphStyle
```
```gql theme={null}
match path = ALL (a {_id:'fatima'})-[:lives_in]->(b)<-[:lives_in]-(c)
return COLLECT_LIST(c) as residents
next
return reduce (geo_mean_product = 1, resident in residents | resident.income * geo_mean_product) ^ (1.0 / LENGTH(residents)) as income_geometric_mean;
```
Note that we first use the [COLLECT\_LIST](/docs/functions/collect-list) to get all the people who live in the same city as Fatima in a LIST. Next we use the [REDUCE](/docs/functions/reduce) to calculate the Geometric Mean.
An alternate way to calculate Geometric Mean would be:
```gql theme={null}
match path = ALL (a {_id:'fatima'})-[:lives_in]->(b)<-[:lives_in]-(c)
return exp(AVG(ln(c.income))) as income_geometric_mean;
```
# REDUCE
Source: https://gql.ch/docs/functions/reduce
REDUCE function applies a lambda value expression to each element in a list, perform cumulative calculations, and return a single value.
### Syntax
```gql theme={null}
reduce(accumulator = initial_value, variable IN list | expression)
```
### Aggregate weights along PATH(s) in GQL
Suppose we are interested in the Uroosa's aggregated percentage in Hotel Kitchen Sink
```mermaid theme={null}
%%{init: {'theme':'base', 'themeVariables': {'lineColor':'#F1FA8C','secondaryColor':'#F1FA8C','background':'#282A36'}}}%%
graph TB
fatima[:person
Fatima ๐ฉ]
uroosa[:person
Uroosa ๐ฉ]
zainab[:person
Zainab ๐ฉ]
hannah[:person
Hannah ๐ฉ]
maryam[:person
Maryam ๐ฉ]
acmecorp[:business
Acme Corp. ๐ข]
northwind[:business
Northwind ๐ข]
fourthcoffee[:business
Fourth Coffee โ๐ข]
tasmaniantraders[:business
Tasmanian Traders ๐ข]
coffeecorp[:business
Coffee Corp. โ๐ข]
blueyonder[:business
Blue Yonder ๐ข]
hotelkitchensink[:business
Hotel Kitchen Sink ๐จ]
uroosa -->|:owns
0.80| acmecorp
fatima -->|:owns
0.20| acmecorp
uroosa -->|:owns
0.15| hotelkitchensink
hannah -->|:owns
0.25| hotelkitchensink
northwind -->|:owns
0.09| hotelkitchensink
acmecorp -->|:owns
0.30| fourthcoffee
fourthcoffee -->|:owns
0.51| hotelkitchensink
zainab -->|:owns
0.19| fourthcoffee
maryam -->|:owns
1.00| coffeecorp
coffeecorp -->|:owns
0.51| blueyonder
blueyonder -->|:owns
0.51| fourthcoffee
tasmaniantraders -->|:owns
0.49| blueyonder
classDef peoplenodes fill:#BD93F9,stroke-width:0px
class eva,fatima,angela,uroosa,eleni,scott,zainab,hannah,maryam peoplenodes
class northwind,acmecorp businessnodes
classDef subgraphStyle fill:#282A36, stroke-width:0px
class row1,row2,row3 subgraphStyle
```
We can use REDUCE as following:
```gql theme={null}
match path = all (a:person {_id:'uroosa'})-[owns]->{0,} (b:business {_id:'hotel kitchen sink'})
return path,
reduce(total_ownership = 1 , own in owns | total_ownership * own.percentage) as ownership
next
return sum(ownership);
```
Note that we first mutiply Ownership percentages along each path and then the sum up the percentages for the 2 paths.
### Calculating Geometric Mean using REDUCE
Geometric Mean is a measure of central tendency that calculates an average of the data using multiplication instead of addition. For a set of n numbers, the geometric mean is the nth root of the product of those numbers. For example, the geometric mean of the numbers 2, 3, and 14 equals (2 \* 3 \* 14)1/3 = (84)1/3 = 4.37952. Geometric Mean is particularly useful when the data is skewed and a simple average does not work.
Suppose we are interested in the Geometric Mean Income of all the people who live in the same city as Fatima:
```mermaid theme={null}
%%{init: {'theme':'base', 'themeVariables': {'lineColor':'#F1FA8C','secondaryColor':'#F1FA8C','background':'#282A36'}}}%%
graph LR
subgraph row1[" "]
saqib[:person
name: Saqib๐จ
income: 375000]
scott[:person
name: Scott ๐จ
income: 205000]
fatima[:person
name: Fatima ๐ฉ
income: 195000]
hannah[:person
name: Hannah ๐ฉ
income: 185000]
zainab[:person
name: Zainab ๐ฉ
income: 190000]
capitola[:city
name:Capitola]
end
subgraph row2[" "]
eleni[:person
name: Eleni ๐ฉ
income: 185000]
uroosa[:person
name: Uroosa ๐ฉ
income: 175000]
angela[:person
name: Angela ๐ฉ
income: 195000]
maryam[:person
name: Maryam ๐ฉ
income: 155000]
santacruz[:city
name:Santa Cruz]
end
subgraph row3[" "]
laila[:person
name: Laila ๐ฉ
income: 180000]
huda[:person
name: Huda ๐ฉ
income: 172000]
end
%% saqib -->|:relationship
type: co-worker| fatima
%% fatima -->|:relationship
type: friend| eleni
%% eleni -->|:relationship
type: friend| uroosa
%% saqib -->|:relationship
type: friend| angela
%% angela -->|:relationship
type: co-worker| scott
%% scott -->|:relationship
type: friend| uroosa
saqib -->|:lives_in| capitola
scott -->|:lives_in| capitola
fatima -->|:lives_in| capitola
hannah -->|:lives_in| capitola
zainab -->|:lives_in| capitola
angela -->|:lives_in| santacruz
uroosa -->|:lives_in| santacruz
eleni -->|:lives_in| santacruz
maryam -->|:lives_in| santacruz
classDef nodes fill:#BD93F9,stroke-width:0px
class saqib,fatima,angela,uroosa,eleni,scott,maryam,zainab,hannah,huda,laila nodes
classDef subgraphStyle fill:#282A36, stroke-width:0px
class row1,row2,row3 subgraphStyle
```
```gql theme={null}
match path = ALL (a {_id:'fatima'})-[:lives_in]->(b)<-[:lives_in]-(c)
return COLLECT_LIST(c) as residents
next
return reduce (geo_mean_product = 1, resident in residents | resident.income * geo_mean_product) ^ (1.0 / LENGTH(residents)) as income_geometric_mean;
```
Note that we first use the [COLLECT\_LIST](/docs/functions/collect-list) to get all the people who live in the same city as Fatima in a LIST. Next we use the [REDUCE](/docs/functions/reduce) to calculate the Geometric Mean.
An alternate way to calculate Geometric Mean would be:
```gql theme={null}
match path = ALL (a {_id:'fatima'})-[:lives_in]->(b)<-[:lives_in]-(c)
return exp(AVG(ln(c.income))) as income_geometric_mean;
```
# CALL
Source: https://gql.ch/docs/querying/call
CALL statement in GQL invokes a Procedure
## For each node find the number of incoming edges
Suppose we are interested in the number of highways flowing into each of the Highway:
```mermaid theme={null}
%%{init: {'theme':'base', 'themeVariables': {'lineColor':'#F1FA8C','secondaryColor':'#F1FA8C','background':'#282A36'}}}%%
graph TB
highway1(:freeway ๐ฃ๏ธ
name: Highway 1)
highway2(:freeway ๐ฃ๏ธ
name: Highway 2)
highway3(:freeway ๐ฃ๏ธ
name: Highway 3)
highway4(:freeway ๐ฃ๏ธ
name: Highway 4)
highway5(:freeway ๐ฃ๏ธ
name: Highway 5)
highway6(:freeway ๐ฃ๏ธ
name: Highway 6)
highway7(:freeway ๐ฃ๏ธ
name: Highway 7)
highway8(:freeway ๐ฃ๏ธ
name: Highway 8)
highway9(:freeway ๐ฃ๏ธ
name: Highway 9)
highway10(:freeway ๐ฃ๏ธ
name: Highway 10)
highway11(:freeway ๐ฃ๏ธ
name: Highway 11)
highway12(:freeway ๐ฃ๏ธ
name: Highway 12)
highway13(:freeway ๐ฃ๏ธ
name: Highway 13)
highway1 -->|:links_to| highway3
highway2 -->|:links_to| highway3
highway3 -->|:links_to| highway4
highway3 -->|:links_to| highway6
highway4 -->|:links_to| highway5
highway6 -->|:links_to| highway7
highway5 -->|:links_to| highway8
highway7 -->|:links_to| highway8
highway9 -->|:links_to| highway10
highway11 -->|:links_to| highway12
highway8 -->|:links_to| highway12
highway10 -->|:links_to| highway12
highway12 -->|:links_to| highway13
classDef nodes fill:#BD93F9,stroke-width:0px
class highway1,highway2,highway3,highway4,highway5,highway6,highway7,highway8,highway9,highway10,highway11,highway12,highway13 nodes
```
We can use the CALL statement to invoke and inline procedure as follows:
```gql theme={null}
MATCH nodes = (b)
CALL {
MATCH path = (a)-[e1:flows_to]->(b)
return path
, count(distinct e1) as incoming_nodes_count
, COLLECT_LIST(distinct a.name) as incoming_nodes
}
return table(b.name, incoming_nodes_count, incoming_nodes)
order by incoming_nodes_count desc;
```
## For each node list paths to all other nodes
We are interested in getting all paths from each to all other nodes:
```mermaid theme={null}
%%{init: {'theme':'base', 'themeVariables': {'lineColor':'#F1FA8C','secondaryColor':'#F1FA8C','background':'#282A36'}}}%%
graph TB
highway1(:freeway ๐ฃ๏ธ
name: Highway 1)
highway2(:freeway ๐ฃ๏ธ
name: Highway 2)
highway3(:freeway ๐ฃ๏ธ
name: Highway 3)
highway4(:freeway ๐ฃ๏ธ
name: Highway 4)
highway5(:freeway ๐ฃ๏ธ
name: Highway 5)
highway6(:freeway ๐ฃ๏ธ
name: Highway 6)
highway7(:freeway ๐ฃ๏ธ
name: Highway 7)
highway8(:freeway ๐ฃ๏ธ
name: Highway 8)
highway9(:freeway ๐ฃ๏ธ
name: Highway 9)
highway10(:freeway ๐ฃ๏ธ
name: Highway 10)
highway11(:freeway ๐ฃ๏ธ
name: Highway 11)
highway12(:freeway ๐ฃ๏ธ
name: Highway 12)
highway13(:freeway ๐ฃ๏ธ
name: Highway 13)
highway1 -->|:links_to| highway3
highway2 -->|:links_to| highway3
highway3 -->|:links_to| highway4
highway3 -->|:links_to| highway6
highway4 -->|:links_to| highway5
highway6 -->|:links_to| highway7
highway5 -->|:links_to| highway8
highway7 -->|:links_to| highway8
highway9 -->|:links_to| highway10
highway11 -->|:links_to| highway12
highway8 -->|:links_to| highway12
highway10 -->|:links_to| highway12
highway12 -->|:links_to| highway13
classDef nodes fill:#BD93F9,stroke-width:0px
class highway1,highway2,highway3,highway4,highway5,highway6,highway7,highway8,highway9,highway10,highway11,highway12,highway13 nodes
```
```gql theme={null}
MATCH nodes = (a)
CALL {
MATCH path = (a)-[edges:flows_to]->{0,}(b)
return reduce(path = a._id, edge in edges | path || '->' || edge._to) as route
, b
}
return table(a.name as starting, b.name as ending, route)
```
## Movie recommendations based on what the 1 degree connection and 2nd degree connection have watched
```mermaid theme={null}
%%{init: {'theme':'base', 'themeVariables': {'lineColor':'#F1FA8C','secondaryColor':'#F1FA8C','background':'#282A36'}}}%%
graph TB
subgraph row1[" "]
Maryam(:account ๐ง
name: Maryam)
Sara(:account ๐ง
name: Sara)
Uroosa(:account ๐ง
name: Uroosa)
Fatima(:account ๐ง
name: Fatima)
Zainab(:account ๐ง
name: Zainab)
Hannah(:account ๐ง
name: Hannah)
end
subgraph row2[" "]
despicable_me(:movie ๐ฌ
name: Despicable Me)
penguins_of_madagascar(:movie ๐ฌ
name: Penguins of Madagascar)
time_hoppers(:movie ๐ฌ
name: Time Hoppers)
zootopia(:movie ๐ฌ
name: Zootopia)
end
Sara <-->|:friend| Uroosa
Uroosa <-->|:friend| Maryam
Maryam <-->|:friend| Fatima
Zainab <-->|:friend| Hannah
Sara -->|:watched ๐| zootopia
Uroosa -->|:watched ๐| penguins_of_madagascar
Maryam -->|:watched ๐| time_hoppers
Fatima -->|:watched ๐| time_hoppers
Zainab -->|:watched ๐| time_hoppers
Fatima -->|:watched ๐| despicable_me
Hannah -->|:watched ๐| despicable_me
classDef nodes fill:#BD93F9,stroke-width:0px
class Maryam,Sara,Uroosa,Fatima,Hannah,Zainab,highway7,highway8,highway9,highway10,highway11,highway12,highway13 nodes
classDef subgraphStyle fill:#282A36, stroke-width:0px
class row1,row2,row3 subgraphStyle
```
Recommend movies based on what account 1st and 2nd degree connection have watched:
```gql theme={null}
MATCH friends = ALL (account_a)-[:friends]->{0,2}(account_b)
CALL {
MATCH path = (account_a)-[:watched]->(movie_a)
, (account_b)-[:watched]->(movie_b)
FILTER account_a <> account_b and movie_a <> movie_b
return path
, COLLECT_LIST(distinct movie_a.title) as recommended_movies
}
FILTER account_a <> account_b
return table(account_a.name, account_b.name, recommended_movies);
```
# FILTER
Source: https://gql.ch/docs/querying/filter
The `FILTER` statement selects a subset of the records of the current working table. It updates the current working table to include only the records that satisfy the specified search condition. Compare this to the [WHERE](/docs/querying/where) clause which allows selection of records during the [MATCH](/docs/querying/match) phase. The FILTER statement is applied after the precending statements have been executed. As such, it is most useful in refining the results further by applying additional conditions.
`FILTER` clause is used to apply conditional filters on nodes, relationships, or properties after a pattern is matched. It supports standard logical operators like AND, OR, NOT, and comparison operators such as `=`, `<`, `>`, and `IN`.
```gql theme={null}
MATCH (e: Event )
FILTER e.timestamp > "2026โ03โ01" AND e.cost <= 200
RETURN e
```
This retrieves all events that occurred after March 1st, 2026, with a cost no greater than 200.
`FILTER` is often paired with [MATCH](/docs/querying/match), but can also follow [WITH](/docs/querying/with) to filter aggregated results.
# FOR
Source: https://gql.ch/docs/querying/for
`FOR` statement unnests a list into individual records by iterating over its elements, allowing subsequent statements to process these elements one by one.
### Using FOR statement to iterate over each edge in a Quantified Path Pattern
Suppose we are interested in the all the hops required to go from Bayreuth to Santiago:
```mermaid theme={null}
%%{init: {'theme':'base', 'themeVariables': {'lineColor':'#F1FA8C','secondaryColor':'#F1FA8C','background':'#282A36'}}}%%
graph TB
n1[Bayreuth, Germany ๐ฉ๐ช]
n2[Nรผrnberg, Germany ๐ฉ๐ช]
n3[Stuttgart, Germany ๐ฉ๐ช]
n4[Frankfurt, Germany ๐ฉ๐ช]
n5[Paris, France ๐ซ๐ท]
n6[Amsterdam, Netherlands ๐ณ๐ฑ]
n7[Rome, Italy ๐ฎ๐น]
n8[Santiago, Chile ๐จ๐ฑ]
n1 -->|train ๐| n2
n2 -->|train ๐| n1
n2 -->|train ๐
duration = 120| n3
n2 -->|train ๐| n4
n4 -->|train ๐| n5
n3 -->|train ๐| n5
n5 -->|flight โ๏ธ
code = AF406
duration = 780| n8
n6 -->|flight โ๏ธ| n8
n6 -->|flight โ๏ธ| n7
n7 -->|car ๐
tolls = 74| n1
n4 -->|train ๐| n6
classDef cityNode fill:#BD93F9,stroke-width:0px
class n1,n2,n3,n4,n5,n6,n7,n8 cityNode
```
We can use the FOR loop as following
```gql theme={null}
match paths = any shortest (a:city {_id:'Bayreuth'})-[edges:train|flight]->{1,}(b:city {_id:'Santiago'})
for edge in edges
return distinct table(edge._from, edge._to, labels(edge), pnodeIds(paths), length(paths));
```
We are using the FOR statement to unnest (decompose) the edges.
# MATCH
Source: https://gql.ch/docs/querying/match
Ascii-art `()-[]->()` syntax for expressing patterns.
A [GQL](https://gql.net) query typically begins with the `MATCH` clause, which identifies a graph pattern to search for in the data. It is the foundation for querying nodes, relationships, and their properties. The `MATCH` clause specifies the structural shape of the subgraph being queried.
```gql theme={null}
MATCH (u: User)โ[:PERFORMED]โ>(e: Event {activity: 'Submit'})
```
In this example, the pattern searches for users who performed an event labeled "Submit". The nodes (`u`, `e`) are labeled with semantic roles, and the relationship `[:PERFORMED]` describes the interaction between them.
Patterns can include multiple relationships and variable-length traversals using the `{m,n}` quantifier. For example, `[:FOLLOWS]->{,3}` matches up to 3 levels of consecutive FOLLOWS relationships. The `MATCH` clause is frequently used in combination with [WHERE](/docs/querying/where), [RETURN](/docs/querying/return), and [WITH](/docs/querying/with) clauses to build complex queries.
## Variable Binding in GQL
Retrieve all the teachers who liked a comment made by students who they know since 2021 or earlier:
```mermaid theme={null}
%%{init: {'theme':'base', 'themeVariables': {'lineColor':'#F1FA8C','secondaryColor':'#F1FA8C','background':'#282A36'}}}%%
graph LR
fatima[:Teacher
name: Fatima ๐ฉ
status: Active]
uroosa[:Student
name: Uroosa ๐ฉ
status: Active]
comment_1[:comment
content: I love GQL
comment_date:2025-01-01
]
fatima -->|:knowns
since:2025| uroosa
fatima -->|:likes| comment_1
comment_1 -->|:author| uroosa
classDef nodes fill:#BD93F9,stroke-width:0px
class eva,fatima,angela,uroosa,eleni,scott nodes
classDef subgraphStyle fill:#282A36, stroke-width:0px
class row1,row2,row3 subgraphStyle
```
```gql theme={null}
MATCH path = (x:teacher)-[:likes ]->
(:comment)-[:author]->
(:student)-[y:knows WHERE y.since < 2021]->(x)
```
Here we are binding a `:teacher`-labelled node to the variable `x` and requiring there be a `:likes`-labelled edge to a node representing a `comment`. In GQL ASCII-art syntax, round brackets represent nodes, while square brackets represent edges. We then require this comment to have been made by a student (represented by an `:author` edge to a node with the label `student`). Finally, we require this student to have any edge to the original node bound to `x`, that this edge is labelled with `:knows` and that the value of its since attribute is greater than 2021
## Shortest Path
Find shortest path `path`, from a user `u1` to user `u2` traversing `:knows` edges 1+ (`{1,}`) times.
```mermaid theme={null}
%%{init: {'theme':'base', 'themeVariables': {'lineColor':'#F1FA8C','secondaryColor':'#F1FA8C','background':'#282A36'}}}%%
graph TB
saqib[Saqib ๐จ]
fatima[Fatima ๐ฉ]
scott[Scott ๐จ]
eleni[Eleni ๐ฉ]
uroosa[Uroosa ๐ฉ]
angela[Angela ๐ฉ]
saqib -->|co-worker| fatima
fatima -->|friend| eleni
eleni -->|friend| uroosa
saqib -->|friend| angela
angela -->|co-worker| scott
scott -->|friend| uroosa
classDef nodes fill:#BD93F9,stroke-width:0px
class saqib,fatima,angela,uroosa,eleni,scott nodes
```
```gql theme={null}
MATCH path = ANY SHORTEST (u1:users {username: "saqib"})-
[:knows]->{1,}(t2:users {username: "uroosa"})
RETURN u1.username, u2.username, path_length(p) AS num_hops
```
## Expressing complex queries using Multiple Paths
Find a pair of friends in the same city (`(y.city = x.city)`) who transfer money (`(account_x)โ[t1:transfer]โ>(account_z)โ[t2:transfer]โ>(account_y)`) to each other using a common friend who lives elsewhere (`(x.city<>z.city)`).
```mermaid theme={null}
%%{init: {'theme':'base', 'themeVariables': {'lineColor':'#F1FA8C','secondaryColor':'#F1FA8C','background':'#282A36'}}}%%
graph LR
subgraph row1[" "]
eva[Eva ๐ฉ
Carmel, CA]
eleni[Eleni ๐ฉ
Santa Cruz, CA]
angela[Angela ๐ฉ
Carmel, CA]
end
subgraph row2[" "]
account_1[Account 1
type: savings
balance: 1000]
account_2[Account 2
type: savings
balance: 3000]
account_3[Account 3
type: checking
balance: 500]
end
eva -->|owns| account_1
eleni -->|owns| account_2
angela -->|owns| account_3
eva <-->|friends| angela
eva <-->|friends| eleni
eleni <-->|friends| angela
account_1 -->|Transfer
amount:20000
timestamp:00001|account_2
account_2 -->|Transfer
amount:15000
timestamp:00002|account_3
classDef nodes fill:#BD93F9,stroke-width:0px
class eva,fatima,angela,uroosa,eleni,scott nodes
classDef subgraphStyle fill:#282A36, stroke-width:0px
class row1,row2,row3 subgraphStyle
```
```gql theme={null}
MATCH (x:account_holder)โ[:friends]โ>(y:account_holder)โ
[:friends]โ>(z:account_holder)โ
[:friends]โ>(x:account_holder)
, (x)โ[:owns]โ>(account_x)
, (y)โ[:owns]โ>(account_y)
, (z)โ[:owns]โ>(account_z)
, (account_x)โ[t1:transfer]โ>(account_z)โ[t2:transfer]โ>(account_y)
FILTER (y.city = x.city) AND (x.city<>z.city)
RETURN x.name AS name1, y.name AS name2
```
This pattern consists of five path patterns, separated by a commas. In GQL, the comma performs a logical join on the results of the two path patterns.
# OPTIONAL MATCH
Source: https://gql.ch/docs/querying/optional-match
Use OPTIONAL MATCH to find patterns that might not exist, returning empty values when patterns don't match. The OPTIONAL MATCH clause works like MATCH but allows parts of the pattern to be missing. It preserves nulls in the result when the pattern does not fully match, similar to a left outer join in
relational databases.
### Return nodes where the relationship may not exist
Suppose we are interested all the persons who have income of greater and 185000 and not live in Capitola.
```mermaid theme={null}
%%{init: {'theme':'base', 'themeVariables': {'lineColor':'#F1FA8C','secondaryColor':'#F1FA8C','background':'#282A36'}}}%%
graph LR
subgraph row1[" "]
saqib[:person
name: Saqib๐จ
income: 375000]
scott[:person
name: Scott ๐จ
income: 205000]
fatima[:person
name: Fatima ๐ฉ
income: 195000]
hannah[:person
name: Hannah ๐ฉ
income: 185000]
zainab[:person
name: Zainab ๐ฉ
income: 190000]
capitola[:city
name:Capitola]
end
subgraph row2[" "]
eleni[:person
name: Eleni ๐ฉ
income: 185000]
uroosa[:person
name: Uroosa ๐ฉ
income: 175000]
angela[:person
name: Angela ๐ฉ
income: 195000]
maryam[:person
name: Maryam ๐ฉ
income: 155000]
santacruz[:city
name:Santa Cruz]
end
subgraph row3[" "]
laila[:person
name: Laila ๐ฉ
income: 180000]
huda[:person
name: Huda ๐ฉ
income: 172000]
end
%% saqib -->|:relationship
type: co-worker| fatima
%% fatima -->|:relationship
type: friend| eleni
%% eleni -->|:relationship
type: friend| uroosa
%% saqib -->|:relationship
type: friend| angela
%% angela -->|:relationship
type: co-worker| scott
%% scott -->|:relationship
type: friend| uroosa
saqib -->|:lives_in| capitola
scott -->|:lives_in| capitola
fatima -->|:lives_in| capitola
hannah -->|:lives_in| capitola
zainab -->|:lives_in| capitola
angela -->|:lives_in| santacruz
uroosa -->|:lives_in| santacruz
eleni -->|:lives_in| santacruz
maryam -->|:lives_in| santacruz
classDef nodes fill:#BD93F9,stroke-width:0px
class saqib,fatima,angela,uroosa,eleni,scott,maryam,zainab,hannah,huda,laila nodes
classDef subgraphStyle fill:#282A36, stroke-width:0px
class row1,row2,row3 subgraphStyle
```
```gql theme={null}
MATCH (resident:person WHERE resident.income > 185000)
OPTIONAL MATCH (resident)-[:lives_is]->(c:city)
WHERE c.name <> 'Capitola'
RETURN p.name as Person, c.name as City
```
This query finds all Person nodes where the income is greater than 185000, and optionally matches cities they're connected to (excluding Capitola). If a person isn't connected to any city, the City column returns empty, but the person is still included in the results.
Output
The optional match ensures that people without city connections are still returned
| Person | City |
| ------ | ---------- |
| Angela | Santa Cruz |
| Huda | |
# RETURN
Source: https://gql.ch/docs/querying/return
The [GQL](https://gql.net) RETURN clause is used to specify the output of the query. It typically follows a [MATCH](/docs/querying/match) clause and allows the user to retrieve nodes, relationships, or specific properties from the matched subgraph.
```gql theme={null}
MATCH (u: User)โ[:PERFORMED]โ>(e: Event{activity: 'Submit'})
RETURN u.name
```
This query returns the name of each user who has performed the Submit activity. Expressions within the RETURN clause can also include computed values, aggregations, and projections. The result set can be further refined with sorting or deduplication using clauses like ORDER BY and DISTINCT.
# WHERE
Source: https://gql.ch/docs/querying/where
`WHERE` clause allows for filtering during the [MATCH](/docs/querying/match) phase. Compare this to the [FILTER](/docs/querying/filter) statment which allows results to be filtered after previous steps. The WHERE clause is part of the MATCH statement and is evaluated during the graph pattern-matching process. As such, it influences the PATH(s) returned by the [MATCH](/docs/querying/match) statement.
## Using WHERE clause in the Node and Edge Selection
Select all comments that posted after 2025-01-01
```mermaid theme={null}
%%{init: {'theme':'base', 'themeVariables': {'lineColor':'#F1FA8C','secondaryColor':'#F1FA8C','background':'#282A36'}}}%%
graph LR
fatima[:Teacher
name: Fatima ๐ฉ
status: Active]
uroosa[:Student
name: Uroosa ๐ฉ
status: Active]
comment_1[:comment
content: I love GQL
comment_date:2025-01-01
]
fatima -->|:knowns
since:2025| uroosa
fatima -->|:likes| comment_1
comment_1 -->|:author| uroosa
classDef nodes fill:#BD93F9,stroke-width:0px
class eva,fatima,angela,uroosa,eleni,scott nodes
classDef subgraphStyle fill:#282A36, stroke-width:0px
class row1,row2,row3 subgraphStyle
```
```gql theme={null}
USE graph social_network;
MATCH (x:comment WHERE x.comment_date > '2025-01-01')-[z:author]->(y)
RETURN y.name AS student_name, x.content AS comment_content
```
The first line selects the database to query, namely social\_network, and the second one specifies a path pattern to match in the graph. The last line defines what to return from the matched pattern.
The path pattern in the [MATCH](/docs/querying/match) pattern consists of three subpatterns, listed from left to right as they appear in the query. The first one matches any node, noted by `()`, where the `comment_date` is greater than '2025-01-01', storing identifiers in variable `x`. The second subpattern matches directional edges, captured by `-[]->`,that have an `author` label, and binding them to variable `z`. Finally, the third one matches any node, storing identifiers in y. Each of these subpatterns yields a set of paths, where a path is defined as an alternating sequence of nodes and edges, starting and ending with a node. In particular, edge patterns yield the edgeโs identifier and include the connected nodes that form the path.
# WITH
Source: https://gql.ch/docs/querying/with
[GQL](https://gql.net) `WITH` clause allows for chaining queries and controlling the scope of variables passed between query parts. It is especially useful for aggregation, filtering on intermediate results, or renaming fields. Any variable not explicitly passed with `WITH` is no longer available in the next part of the query.
```gql theme={null}
MATCH (u:User)โ[:PERFORMED]โ>(e: Event)
WITH u.name AS user, count (e) AS frequency
WHERE frequency > 3
RETURN user, frequency
```
Here, `WITH` is used to aggregate the number of events each user has performed,then [WHERE](/docs/querying/where) is used to filter users who performed more than three events. This pattern is common in analytical queries where results need to be aggregated and filtered.
# GPML
Source: https://gql.ch/gpml
Graph Pattern Matching Language (GPML)
# Background
The International Standards Committee Working Group develops the [GQL](https://gql.net) standard for Database Languages (WG3), which is also responsible for maintaining and enhancing SQL. This team consists of experts from both academia and industry. The SQL/PGQ (Property Graph Queries) part is a new addition to the SQL standard, which was developed alongside [GQL](https://gql.net). [GQL](https://gql.net) is a property graph query language. In [GQL](https://gql.net), a property graph can be an undirected graph, a directed graph, or a combination of both: partially directed.
# Graph Pattern Matching Language (GPML)
[Graph query languages](https://gql.net) extract data from a graph by matching a given graph pattern. This is accomplished using the Graph Pattern Matching Language (GPML), which enables you to define a set of path patterns. Such a path pattern maps graph vertices and edges to variables through variable binding, which can be used to reference graph elements, their labels and their properties. GPML, defined in [GQL](https://gql.net), draws much inspiration from the Open-Cypher query language. The overall way of writing a pattern-matching query in both languages is the same. To better understand how GPML works, let's take a brief tour of its core syntax. We will use the following Graph with `FRIEND` and `WATCHED` relationships to illustrate the syntax:
```mermaid theme={null} theme={null} theme={null} theme={null} theme={null} theme={null}
%%{init: {'theme':'base', 'themeVariables': {'lineColor':'#F1FA8C','secondaryColor':'#F1FA8C','background':'#282A36'}}}%%
graph TB
subgraph row1[" "]
Maryam(:account ๐ง
name: Maryam)
Sara(:account ๐ง
name: Sara)
Uroosa(:account ๐ง
name: Uroosa)
Fatima(:account ๐ง
name: Fatima)
Zainab(:account ๐ง
name: Zainab)
Hannah(:account ๐ง
name: Hannah)
end
subgraph row2[" "]
despicable_me(:movie ๐ฌ
name: Despicable Me)
penguins_of_madagascar(:movie ๐ฌ
name: Penguins of Madagascar)
time_hoppers(:movie ๐ฌ
name: Time Hoppers)
zootopia(:movie ๐ฌ
name: Zootopia)
end
Sara <-->|:friend| Uroosa
Uroosa <-->|:friend| Maryam
Maryam <-->|:friend| Fatima
Zainab <-->|:friend| Hannah
Sara -->|:watched ๐| zootopia
Uroosa -->|:watched ๐| penguins_of_madagascar
Maryam -->|:watched ๐| time_hoppers
Fatima -->|:watched ๐| time_hoppers
Zainab -->|:watched ๐| time_hoppers
Fatima -->|:watched ๐| despicable_me
Hannah -->|:watched ๐| despicable_me
classDef nodes fill:#BD93F9,stroke-width:0px
class Maryam,Sara,Uroosa,Fatima,Hannah,Zainab,highway7,highway8,highway9,highway10,highway11,highway12,highway13 nodes
classDef subgraphStyle fill:#282A36, stroke-width:0px
class row1,row2,row3 subgraphStyle
```
GPML is designed to be intuitive and visual, often described as "ASCII-art" for graphs. At its most basic, a node is represented by parentheses and an edge is represented by square brackets. A variable can be assigned to a node to reference it later, like so: `(x)`. This pattern matches any single node in the graph, binding it to the variable `x`.
Labels and properties can be added to query more specific nodes. A node label specifies the type of the node and it is expressed with a colon as prefix. For example, `(x:ACCOUNT)` will only match nodes with the label `ACCOUNT`. We can further filter nodes by specifying key-value pairs, or properties, inside curly braces: `(x:ACCOUNT {name: 'Uroosa'})`. This pattern will only match `ACCOUNT` nodes where the `name` property is exactly `'Uroosa'`.
Edges are represented using arrows between nodes. A directed edge is drawn with `->` or `<-`, while undirected edges use a simple dash `-`. Similar to nodes, edges can be assigned variables, have labels (often called types), and contain properties. For example, `-[e:WATCHED]->` represents a directed edge bound to the variable `e` with the label `WATCHED`. An edge pattern also supports specifying a property filter similarly to how this is done for nodes. By combining these elements, we can form expressive path patterns. A complete pattern describes a sequence of nodes and the edges that connect them. For instance, the pattern:
```gql theme={null}
(a:ACCOUNT {name: 'Uroosa'})-[e:WATCHED]->(m:MOVIE)
```
searches for a specific `ACCOUNT` node named `'Uroosa'` (bound to `a`), connected by ย `WATCHED` relationship (bound to `e`) to any other `MOVIE` node (bound to `m)`. This simple, declarative syntax allows users to easily express complex structural queries to retrieve data from the graph.
### Multi-hop traversal
Furthermore, these path patterns can be chained together to describe longer, more complex traversals. For example, the pattern:
```gql theme={null}
(a:ACCOUNT)-[:WATCHED]->(m:MOVIE)<-[:WATCHED]-(b:ACCOUNT)
```
would find all pairs of `ACCOUNT` that watched the same `MOVIE` `m`.
### Multiple patterns matching
A query can also contain multiple patterns, separated by a comma. This allows for reusing variables to create more complex conditions. For instance, the pattern:
```gql theme={null}
(a:ACCOUNT)-[:WATCHED]->(m:MOVIE)<-[:WATCHED]-(b:ACCOUNT)
, (a)-[:FRIEND]->(b)
```
extends the previous query to include a predicate such that `a` and `b` ALSO have a `FRIEND` relationship between them. This comma separated patterns effectively join the results of two distinct patterns on the common variables `a` and `b`.
### Variable-length path (quantified path pattern)
GPML also supports more advanced constructs to handle complex queries. One of the most powerful features is specifying variable-length paths using a quantifier in the edge pattern. For example, `(a)-[:FRIEND]->{1,}(b)` will find a path of any length greater than one between nodes `a` and `b` using only `FRIEND` relationships. Quantifiers can also specify bounds, such as `{2,5}` to match paths with a length between two and five edges.
### Path variable binding
Finally, an entire path can be bound to a variable, such as: `z = (a)-[:FRIEND]->{1,6}(b)` which allows the pattern to bind the whole sequence of nodes and edges that make up the path `z`.