Spanner Graph queries overview Stay organized with collections Save and categorize content based on your preferences.
Note: This feature is available with the Spanner Enterprise edition and Enterprise Plus edition. For more information, see theSpanner editions overview.
This document provides an overview using the graph query language withSpanner Graph, including its syntax for graph pattern matching,and shows you how to run queries against your graph. WithSpanner Graph, you can run queries to find patterns, traverserelationships, and gain insights from your property graph data.
The examples in this document use the graph schema that you create inSet up and query Spanner Graph. This schema isillustrated in the following diagram:

Run a Spanner Graph query
You can use the Google Cloud console, Google Cloud CLI, client libraries, the RESTAPI, or the RPC API to run a Spanner Graph query.
Google Cloud console
The following steps show you how to run a query in theGoogle Cloud console. These steps assume you have an instance namedtest-instance that contains a database namedexample-db. For informationabout how to create an instance with a database, seeSet up and query Spanner Graph.
In the Google Cloud console, go to theSpanner Instances page.
Click the instance named
test-instance.UnderDatabases, click the database named
example-db.Open theSpanner Studio, then clickNew tab or use theeditor tab.
Enter a query into the query editor.
ClickRun.
gcloud CLI
To submit queries using thegcloud CLI command-line tool, dothe following:
If it's not already installed,install the gcloud CLI.
In the gcloud CLI, run the following command:
For more information, seeSpanner CLI quickstart.
REST API
To submit queries using the REST API, use one of the following commands:
For more information, seeQuery data using the REST APIandGet started with Spanner using REST.
RPC API
To submit queries using the RPC API, use one of the following commands:
Client libraries
To learn more about how to run a query with a Spanner clientlibrary, see the following:
- Query using the Spanner C++ client library
- Query using the Spanner C# client library
- Query using the Spanner Go client library
- Query using the Spanner Java client library
- Query using the Spanner Node.js client library
- Query using the Spanner PHP client library
- Query using the Spanner Python client library
- Query using the Spanner Ruby client library
For more information about the Spanner client libraries, see theSpanner client libraries overview.
Visualize Spanner Graph query results
You can view a visual representation of your Spanner Graph query results inSpanner Studio in the Google Cloud console. A query visualization lets yousee how the returned elements (nodes and edges) are connected. This can revealpatterns, dependencies, and anomalies that are difficult to see when you viewthe results in a table. To view a visualization of a query, the query mustreturn full nodes in JSON format. Otherwise, you can see the query results inonly tabular format. For more information, seeUse Spanner Graph query visualizations.
Spanner Graph query structure
A Spanner Graph query consists of several components, such as the propertygraph name, node and edge patterns, and quantifiers. You use these components tocreate a query that finds specific patterns in your graph. Each component isdescribed in theGraph pattern matching section of this document.
The query in Figure 2 demonstrates the basic structure of aSpanner Graph query. The query starts by specifying the targetgraph,FinGraph, using theGRAPH clause. TheMATCH clause then defines thepattern to search for. In this case, it's aPerson node connected to anAccount node through anOwns edge. TheRETURN clause specifies whichproperties of the matched nodes to return.

Graph pattern matching
Graph pattern matching finds specific patterns within your graph. The most basicpatterns are element patterns, such as node patterns that match nodes and edgepatterns that match edges.
Node patterns
A node pattern matches nodes in your graph. This pattern contains matchingparentheses, which might optionally include a graph pattern variable, a labelexpression, and property filters.
Find all nodes
The following query returns all nodes in the graph. The variablen, a graphpattern variable, binds to the matching nodes. In this case, the node patternmatches all nodes in the graph.
GRAPHFinGraphMATCH(n)RETURNLABELS(n)ASlabel,n.id;This query returnslabel andid:
| label | id |
|---|---|
| Account | 7 |
| Account | 16 |
| Account | 20 |
| Person | 1 |
| Person | 2 |
| Person | 3 |
Find all nodes with a specific label
The following query matches all nodes in the graph that have thePersonlabel.The query returns thelabel and theid,name properties of the matchednodes.
GRAPHFinGraphMATCH(p:Person)RETURNLABELS(p)ASlabel,p.id,p.name;This query returns the following properties of the matched nodes:
| label | id | name |
|---|---|---|
| Person | 1 | Alex |
| Person | 2 | Dana |
| Person | 3 | Lee |
Find all nodes matching a label expression
You can create alabel expressionwith one or more logical operators. For example, the following query matches allnodes in the graph that have either thePerson orAccount label. The graphpattern variablen exposes allpropertiesfrom nodes with thePerson orAccount label.
GRAPHFinGraphMATCH(n:Person|Account)RETURNLABELS(n)ASlabel,n.id,n.birthday,n.create_time;In the following results of this query:
- All nodes have the
idproperty. - Nodes matching the
Accountlabel have thecreate_timeproperty, butdon't have thebirthdayproperty. Thebirthdayproperty isNULLforthese nodes. - Nodes matching the
Personlabel have thebirthdayproperty, but don'thave thecreate_timeproperty. Thecreate_timeproperty isNULLforthese nodes.
| label | id | birthday | create_time |
|---|---|---|---|
| Account | 7 | NULL | 2020-01-10T14:22:20.222Z |
| Account | 16 | NULL | 2020-01-28T01:55:09.206Z |
| Account | 20 | NULL | 2020-02-18T13:44:20.655Z |
| Person | 1 | 1991-12-21T08:00:00Z | NULL |
| Person | 2 | 1980-10-31T08:00:00Z | NULL |
| Person | 3 | 1986-12-07T08:00:00Z | NULL |
NULL doesn't necessarily indicate the absence of a property, because anelement can expose a property with aNULL value. To check the existence of aproperty, use thePROPERTY_EXISTS predicate.Find all nodes matching the label expression and property filter
This query matches all nodes in the graph that have thePerson label and wherethe propertyid is equal to1.
GRAPHFinGraphMATCH(p:Person{id:1})RETURNLABELS(p)ASlabel,p.id,p.name,p.birthday;Here are the query results:
| label | id | name | birthday |
|---|---|---|---|
| Person | 1 | Alex | 1991-12-21T08:00:00Z |
You can use theWHERE clause to form more complex filtering conditions onlabels and properties.
The following query uses theWHERE clause to form a more complex filteringcondition on properties. It matches all nodes in the graph that have thePerson label, and the propertybirthday is before1990-01-10.
GRAPHFinGraphMATCH(p:PersonWHEREp.birthday <'1990-01-10')RETURNLABELS(p)ASlabel,p.name,p.birthday;Here are the query results:
| label | name | birthday |
|---|---|---|
| Person | Dana | 1980-10-31T08:00:00Z |
| Person | Lee | 1986-12-07T08:00:00Z |
Edge patterns
An edge pattern matches edges or relationships between nodes. Edge patterns areenclosed in square brackets ([]) and include symbols such as-,->, or<- to indicate directions. An edge pattern might optionally include a graphpattern variable to bind to matching edges.
Find all edges with matching labels
This query returns all edges in the graph with theTransfers label. The querybinds the graph pattern variablee to the matching edges.
GRAPHFinGraphMATCH-[e:Transfers]->RETURNe.Idassrc_account,e.order_numberHere are the query results:
| src_account | order_number |
|---|---|
| 7 | 304330008004315 |
| 7 | 304120005529714 |
| 16 | 103650009791820 |
| 20 | 304120005529714 |
| 20 | 302290001255747 |
Find all edges matching the label expression and property filter
This query's edge pattern uses a label expression and a property filter to findall edges labeled withTransfers that match a specifiedorder_number.
GRAPHFinGraphMATCH-[e:Transfers{order_number:"304120005529714"}]->RETURNe.IdASsrc_account,e.order_numberHere are the query results:
| src_account | order_number |
|---|---|
| 7 | 304120005529714 |
| 20 | 304120005529714 |
Find all edges using any direction edge pattern
You can use theany direction edge pattern (-[]-) in a query to match edgesin either direction. The following query finds all transfers with a blockedaccount.
GRAPHFinGraphMATCH(account:Account)-[transfer:Transfers]-(:Account{is_blocked:true})RETURNtransfer.order_number,transfer.amount;Here are the query results:
| order_number | amount |
|---|---|
| 304330008004315 | 300 |
| 304120005529714 | 100 |
| 103650009791820 | 300 |
| 302290001255747 | 200 |
Path patterns
A path pattern is built from alternating node and edge patterns.
Find all paths from a specific node using a path pattern
The following query finds all transfers to an account initiated from an accountowned byPerson withid equal to2.
Each matched result represents a path fromPerson{id: 2} through aconnectedAccount using theOwns edge, into anotherAccount using theTransfers edge.
GRAPHFinGraphMATCH(p:Person{id:2})-[:Owns]->(account:Account)-[t:Transfers]->(to_account:Account)RETURNp.idASsender_id,account.idASfrom_id,to_account.idASto_id;Here are the query results:
| sender_id | from_id | to_id |
|---|---|---|
| 2 | 20 | 7 |
| 2 | 20 | 16 |
Quantified path patterns
A quantified pattern repeats a pattern within a specified range.
Match a quantified edge pattern
To find paths of a variable length, you can apply a quantifier to an edgepattern. The following query demonstrates this by finding destination accountsthat are one to three transfers away from a sourceAccount with anid of7.
The query applies the quantifier{1, 3} to the edge pattern-[e:Transfers]->. This instructs the query to match paths that repeat theTransfers edge pattern one, two, or three times. TheWHERE clause is used toexclude the source account from the results. TheARRAY_LENGTH function is usedto access thegroup variablee. For more information,seeaccess group variable.
GRAPHFinGraphMATCH(src:Account{id:7})-[e:Transfers]->{1,3}(dst:Account)WHEREsrc!=dstRETURNsrc.idASsrc_account_id,ARRAY_LENGTH(e)ASpath_length,dst.idASdst_account_id;Here are the query results:
| src_account_id | path_length | dst_account_id |
|---|---|---|
| 7 | 1 | 16 |
| 7 | 1 | 16 |
| 7 | 3 | 16 |
| 7 | 3 | 16 |
| 7 | 2 | 20 |
| 7 | 2 | 20 |
Some rows in the results are repeated. This is because multiple paths that matchthe pattern can exist between the same source and destination nodes, and thequery returns all of them.
Match a quantified path pattern
The following query finds paths betweenAccount nodes with one to twoTransfers edges through intermediate accounts that are blocked.
The parenthesized path pattern is quantified, and itsWHERE clause specifiesconditions for the repeated pattern.
GRAPHFinGraphMATCH(src:Account)((a:Account)-[:Transfers]->(b:Account{is_blocked:true})WHEREa!=b){1,2}-[:Transfers]->(dst:Account)RETURNsrc.idASsrc_account_id,dst.idASdst_account_id;Here are the query results:
| src_account_id | dst_account_id |
|---|---|
| 7 | 20 |
| 7 | 20 |
| 20 | 20 |
Group variables
A graph pattern variable declared in a quantified pattern becomes agroupvariable when accessed outside that pattern. It then binds to an array ofmatched graph elements.
You can access a group variable as an array. Its graph elements are preserved inthe order of their appearance along the matched paths. You can aggregate a groupvariable usinghorizontal aggregation.
Access group variable
In the following example, the variablee is accessed as follows:
- A graph pattern variable bound to a single edge in the
WHEREclausee.amount > 100when it's within the quantified pattern. - A group variable bound to an array of edge elements in
ARRAY_LENGTH(e)intheRETURNstatement when it's outside the quantified pattern. - A group variable bound to an array of edge elements, which is aggregated by
SUM(e.amount)outside the quantified pattern. This is an example ofhorizontal aggregation.
GRAPHFinGraphMATCH(src:Account{id:7})-[e:TransfersWHEREe.amount >100]->{0,2}(dst:Account)WHEREsrc.id!=dst.idLETtotal_amount=SUM(e.amount)RETURNsrc.idASsrc_account_id,ARRAY_LENGTH(e)ASpath_length,total_amount,dst.idASdst_account_id;Here are the query results:
| src_account_id | path_length | total_amount | dst_account_id |
|---|---|---|---|
| 7 | 1 | 300 | 16 |
| 7 | 2 | 600 | 20 |
Path search prefixes
To limit matched paths within groups that share source and destination nodes,you can use theANY,ANY SHORTEST, orANY CHEAPEST pathsearch prefix.You can only apply these prefixes before an entire path pattern, and you can'tapply them inside parentheses.
Match usingANY
The following query finds all reachable unique accounts that are one or twoTransfers away from a givenAccount node.
TheANY path search prefix ensures that the query returns only one pathbetween a unique pair ofsrc anddstAccount nodes. In the followingexample, although you can reach theAccount node with{id: 16} in twodifferent paths from the sourceAccount node, the query returns only one path.
GRAPHFinGraphMATCHANY(src:Account{id:7})-[e:Transfers]->{1,2}(dst:Account)LETids_in_path=ARRAY_CONCAT(ARRAY_AGG(e.Id),[dst.Id])RETURNsrc.idASsrc_account_id,dst.idASdst_account_id,ids_in_path;Here are the query results:
| src_account_id | dst_account_id | ids_in_path |
|---|---|---|
| 7 | 16 | 7,16 |
| 7 | 20 | 7,16,20 |
Match usingANY SHORTEST
TheANY SHORTEST path search prefix returns a single path for each pair ofsource and destination nodes, selected from those with the minimum number ofedges.
For example, the following query finds one of the shortest paths between anAccount node withid7 and anAccount node with anid of20. Thequery considers paths with one to threeTransfers edges.
GRAPHFinGraphMATCHANYSHORTEST(src:Account{id:7})-[e:Transfers]->{1,3}(dst:Account{id:20})RETURNsrc.idASsrc_account_id,dst.idASdst_account_id,ARRAY_LENGTH(e)ASpath_length;Here are the query results:
| src_account_id | dst_account_id | path_length |
|---|---|---|
| 7 | 20 | 2 |
Match usingANY CHEAPEST
TheANY CHEAPEST path search prefix ensures that for each pair of source anddestination accounts, the query returns only one path with the minimum totalcompute cost.
The following query finds a path with the minimum total compute cost betweenAccount nodes. This cost is based on the sum of theamount property of theTransfers edges. The search considers paths with one to threeTransfersedges.
GRAPHFinGraphMATCHANYCHEAPEST(src:Account)-[e:TransfersCOSTe.amount]->{1,3}(dst:Account)LETtotal_cost=sum(e.amount)RETURNsrc.idASsrc_account_id,dst.idASdst_account_id,total_costHere are the query results:
| src_account_id | dst_account_id | total_cost |
|---|---|---|
| 7 | 7 | 900 |
| 7 | 16 | 100 |
| 7 | 20 | 400 |
| 16 | 7 | 800 |
| 16 | 16 | 500 |
| 16 | 20 | 300 |
| 20 | 7 | 500 |
| 20 | 16 | 200 |
| 20 | 20 | 500 |
Graph patterns
A graph pattern consists of one or more path patterns, separated by a comma (,).Graph patterns can contain aWHERE clause, which lets you access all the graphpattern variables in the path patterns to form filtering conditions. Each pathpattern produces a collection of paths.
Match using a graph pattern
The following query identifies intermediary accounts and their owners involvedin transactions amounts exceeding 200, through which funds are transferred froma source account to a blocked account.
The following path patterns form the graph pattern:
- The first pattern finds paths where the transfer occurs from one account toa blocked account using an intermediate account.
- The second pattern finds paths from an account to its owning person.
The variableinterm acts as a common link between the two path patterns, whichrequiresinterm to reference the same element node in both path patterns. Thiscreates an equi-join operation based on theinterm variable.
GRAPHFinGraphMATCH(src:Account)-[t1:Transfers]->(interm:Account)-[t2:Transfers]->(dst:Account),(interm)<-[:Owns]-(p:Person)WHEREdst.is_blocked=TRUEANDt1.amount >200ANDt2.amount >200RETURNsrc.idASsrc_account_id,dst.idASdst_account_id,interm.idASinterm_account_id,p.idASowner_id;Here are the query results:
| src_account_id | dst_account_id | interm_account_id | owner_id |
|---|---|---|---|
| 20 | 16 | 7 | 1 |
Linear query statements
You can chain multiple graph statements together to form a linear querystatement. The statements are executed in the same order as they appear in thequery.
Each statement takes the output from the previous statement as input. Theinput is empty for the first statement.
The output of the last statement is the final result.
For example, you can use linear query statements to find the maximum transfer toa blocked account. The following query finds the account and its owner with thelargest outgoing transfer to a blocked account.
GRAPHFinGraphMATCH(src_account:Account)-[transfer:Transfers]->(dst_account:Account{is_blocked:true})ORDERBYtransfer.amountDESCLIMIT1MATCH(src_account:Account)<-[owns:Owns]-(owner:Person)RETURNsrc_account.idASaccount_id,owner.nameASowner_name;The following table illustrates this process by showing the intermediate resultspassed between each statement. For brevity, only some properties are shown.
| Statement | Intermediate result (abbreviated) | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
MATCH (src_account:Account) -[transfer:Transfers]-> (dst_account:Account {is_blocked:true}) |
| ||||||||||||
ORDER BY transfer.amount DESC |
| ||||||||||||
LIMIT 1 |
| ||||||||||||
MATCH (src_account:Account) <-[owns:Owns]- (owner:Person) |
| ||||||||||||
RETURN src_account.id AS account_id, owner.name AS owner_name |
|
Here are the query results:
| account_id | owner_name |
|---|---|
7 | Alex |
Return statement
TheRETURN statementspecifies what to return from the matched patterns. It can accessgraph pattern variables and include expressions and other clauses, such asORDER BY andGROUP BY.
Spanner Graph doesn't support returning graph elements as query results. Toreturn the entire graph element, use theTO_JSON functionorSAFE_TO_JSON function.Of these two functions, we recommend that you useSAFE_TO_JSON.
Return graph elements as JSON
GRAPHFinGraphMATCH(n:Account{id:7})-- Returning a graph element in the final results is NOT allowed. Instead, use-- the TO_JSON function or explicitly return the graph element's properties.RETURNTO_JSON(n)ASn;GRAPHFinGraphMATCH(n:Account{id:7})-- Certain fields in the graph elements, such as TOKENLIST, can't be returned-- in the TO_JSON function. In those cases, use the SAFE_TO_JSON function instead.RETURNSAFE_TO_JSON(n)ASn;Here are the query results:
| n |
|---|
{"identifier":"mUZpbkdyYXBoLkFjY291bnQAeJEO","kind":"node","labels":["Account"],"properties":{"create_time":"2020-01-10T14:22:20.222Z","id":7,"is_blocked":false,"nick_name":"VacationFund"}} |
Composing larger queries with NEXT keyword
You can chain multiple graph linear query statements using theNEXT keyword.The first statement receives an empty input, and the output of each subsequentstatement becomes the input for the next.
The following example finds the owner of the account with the most incomingtransfers by chaining multiple graph linear statements. You can use the samevariable, for example,account, to refer to the same graph element acrossmultiple linear statements.
GRAPHFinGraphMATCH(:Account)-[:Transfers]->(account:Account)RETURNaccount,COUNT(*)ASnum_incoming_transfersGROUPBYaccountORDERBYnum_incoming_transfersDESCLIMIT1NEXTMATCH(account:Account)<-[:Owns]-(owner:Person)RETURNaccount.idASaccount_id,owner.nameASowner_name,num_incoming_transfers;Here are the query results:
| account_id | owner_name | num_incoming_transfers |
|---|---|---|
16 | Lee | 3 |
Functions and expressions
You can use all GoogleSQLfunctions (both aggregateand scalar functions),operators, andconditional expressionsin Spanner Graph queries. Spanner Graph also supports graph-specificfunctions and operators.
Built-in functions and operators
The followingfunctions andoperators are used inGQL:
PROPERTY_EXISTS(n, birthday): Returns whethernhas thebirthdayproperty.LABELS(n): Returns the labels ofnas defined in the graph schema.PROPERTY_NAMES(n): Returns the property names ofn.TO_JSON(n): Returnsnin JSON format. For more information, see theTO_JSONfunction.
thePROPERTY_EXISTS predicate,LABELS function, andTO_JSON function, aswell as other built-in functions likeARRAY_AGG andCONCAT.
GRAPHFinGraphMATCH(person:Person)-[:Owns]->(account:Account)RETURNperson,ARRAY_AGG(account.nick_name)ASaccountsGROUPBYpersonNEXTRETURNLABELS(person)ASlabels,TO_JSON(person)ASperson,accounts,CONCAT(person.city,", ",person.country)ASlocation,PROPERTY_EXISTS(person,is_blocked)ASis_blocked_property_exists,PROPERTY_EXISTS(person,name)ASname_property_existsLIMIT1;Here are the query results:
| is_blocked_property_exists | name_property_exists | labels | accounts | location | person |
|---|---|---|---|---|---|
false | true | Person | ["Vacation Fund"] | Adelaide, Australia | {"identifier":"mUZpbkdyYXBoLlBlcnNvbgB4kQI=","kind":"node","labels":["Person"],"properties":{"birthday":"1991-12-21T08:00:00Z","city":"Adelaide","country":"Australia","id":1,"name":"Alex"}} |
Subqueries
Asubquery is a query nested in another query. The following listsSpanner Graph subquery rules:
- A subquery is enclosed within a pair of braces
{}. - A subquery might start with the leading
GRAPHclause to specify thegraph in scope. The specified graph doesn't need to be the same as the oneused in the outer query. - When the
GRAPHclause is omitted in the subquery, the following occurs:- The graph in scope is inferred from the closest outer query context.
- The subquery must start from a graph pattern matching statementwith
MATCH.
- A graph pattern variable declared outside the subquery scope can't bedeclared again inside the subquery, but it can be referred to inexpressions or functions inside the subquery.
Use a subquery to find the total number of transfers from each account
The following query illustrates the use of theVALUE subquery. The subquery isenclosed in braces{} prefixed by theVALUE keyword. The query returns the totalnumber of transfers initiated from an account.
GRAPHFinGraphMATCH(p:Person)-[:Owns]->(account:Account)RETURNp.name,account.idASaccount_id,VALUE{MATCH(a:Account)-[transfer:Transfers]->(:Account)WHEREa=accountRETURNCOUNT(transfer)ASnum_transfers}ASnum_transfers;Here are the query results:
| name | account_id | num_transfers |
|---|---|---|
Alex | 7 | 2 |
Dana | 20 | 2 |
Lee | 16 | 1 |
For a list of supported subquery expressions, seeSpanner Graph subqueries.
Use a subquery to find accounts owned by each person
The following query uses theCALL statement with an inline subquery. TheMATCH(p:Person) statement creates a table with a single column namedp.Each row in this table contains aPerson node. TheCALL (p) statementexecutes the enclosed subquery for each row in this working table. The subqueryfinds accounts owned by each matched personp. Multiple accounts for the sameperson are ordered by account ID.
The example declares the outer-scoped node variablep from theMATCH(p:Person) clause. TheCALL (p) statement references this variable. Thisdeclaration lets you redeclare ormultiply-declare the node variable in a pathpattern of the subquery. This ensures that the inner and outerp nodevariables bind to the samePerson node in the graph. If theCALL statementdoesn't declare the node variablep, the subquery treats the redeclaredvariablep as a new variable. This new variable is independent of theouter-scoped variable, and the subquery doesn'tmultiply-declare it becauseit returns different results. For more information, seeCALLstatement.
GRAPHFinGraphMATCH(p:Person)CALL(p){MATCH(p)-[:Owns]->(a:Account)RETURNa.IdASaccount_IdORDERBYaccount_Id}RETURNp.nameASperson_name,account_IdORDERBYperson_name,account_Id;Result
| person_name | account_Id |
|---|---|
| Alex | 7 |
| Dana | 20 |
| Lee | 16 |
Query parameters
You can query Spanner Graph with parameters. For more information, see thesyntax andlearn how toquery data with parametersin the Spanner client libraries.
The following query illustrates the use of query parameters.
GRAPHFinGraphMATCH(person:Person{id:@id})RETURNperson.name;Query graphs and tables together
You can use Graph queries in conjunction with SQL to access information fromyour Graphs and Tables together in a single statement.
TheGRAPH_TABLE operator takes a linear graph query and returns its result ina tabular form that can be integrated into a SQL query. This interoperabilitylets you enrich graph query results with non-graph content and the other wayaround.
For example, you can create aCreditReports table and insert a few creditreports, as shown in the following example:
CREATETABLECreditReports(person_idINT64NOTNULL,create_timeTIMESTAMPNOTNULL,scoreINT64NOTNULL,)PRIMARYKEY(person_id,create_time);INSERTINTOCreditReports(person_id,create_time,score)VALUES(1,"2020-01-10 06:22:20.222",700),(2,"2020-02-10 06:22:20.222",800),(3,"2020-03-10 06:22:20.222",750);Next, you can identify specific persons through graph pattern matching inGRAPH_TABLE and join the graph query results with theCreditReports table toretrieve credit scores.
SELECTgt.person.id,credit.scoreASlatest_credit_scoreFROMGRAPH_TABLE(FinGraphMATCH(person:Person)-[:Owns]->(:Account)-[:Transfers]->(account:Account{is_blocked:true})RETURNDISTINCTperson)ASgtJOINCreditReportsAScreditONgt.person.id=credit.person_idORDERBYcredit.create_time;Here are the query results:
| person_id | latest_credit_score |
|---|---|
1 | 700 |
2 | 800 |
What's next
Learnbest practices for tuning queries.
Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2026-02-19 UTC.