# 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`.