Working with STRUCT objects Stay organized with collections Save and categorize content based on your preferences.
STRUCT data type is not supported in thePostgreSQL interface for Spanner.Spanner allows you to createSTRUCT objects from data, as well as to useSTRUCT objects as bound parameters when running a SQL query with one of theSpanner client libraries.
For more information about theSTRUCT type in Spanner, seeData types.
Declaring a user-defined type of STRUCT object
You can declare aSTRUCT object in queries using the syntax described inDeclaring aSTRUCT type.
You can define a type ofSTRUCT object as a sequence of field names and theirdata types. You can then supply this type along with queries containingSTRUCT-typed parameter bindings and Spanner will use it tocheck that theSTRUCT parameter values in your query are valid.
C++
// Cloud Spanner STRUCT<> types are represented by std::tuple<...>. The// following represents a STRUCT<> with two unnamed STRING fields.usingNameType=std::tuple<std::string,std::string>;C#
varnameType=newSpannerStruct{{"FirstName",SpannerDbType.String,null},{"LastName",SpannerDbType.String,null}};Go
typenameTypestruct{FirstNamestringLastNamestring}Java
TypenameType=Type.struct(Arrays.asList(StructField.of("FirstName",Type.string()),StructField.of("LastName",Type.string())));Node.js
constnameType={type:'struct',fields:[{name:'FirstName',type:'string',},{name:'LastName',type:'string',},],};PHP
$nameType = new ArrayType( (new StructType) ->add('FirstName', Database::TYPE_STRING) ->add('LastName', Database::TYPE_STRING));Python
name_type=param_types.Struct([param_types.StructField("FirstName",param_types.STRING),param_types.StructField("LastName",param_types.STRING),])Ruby
name_type=client.fieldsFirstName::STRING,LastName::STRINGCreating STRUCT objects
The following sample shows how to createSTRUCT objects using theSpanner client libraries.
C++
// Cloud Spanner STRUCT<> types are represented by std::tuple<...>. The// following represents a STRUCT<> with two unnamed STRING fields.usingNameType=std::tuple<std::string,std::string>;autosinger_info=NameType{"Elena","Campbell"};C#
varnameStruct=newSpannerStruct{{"FirstName",SpannerDbType.String,"Elena"},{"LastName",SpannerDbType.String,"Campbell"},};Go
typenamestruct{FirstNamestringLastNamestring}varsingerInfo=name{"Elena","Campbell"}Java
Structname=Struct.newBuilder().set("FirstName").to("Elena").set("LastName").to("Campbell").build();Node.js
// Imports the Google Cloud client libraryconst{Spanner}=require('@google-cloud/spanner');constnameStruct=Spanner.struct({FirstName:'Elena',LastName:'Campbell',});PHP
$nameValue = (new StructValue) ->add('FirstName', 'Elena') ->add('LastName', 'Campbell');$nameType = (new StructType) ->add('FirstName', Database::TYPE_STRING) ->add('LastName', Database::TYPE_STRING);Python
record_type=param_types.Struct([param_types.StructField("FirstName",param_types.STRING),param_types.StructField("LastName",param_types.STRING),])record_value=("Elena","Campbell")Ruby
name_struct={FirstName:"Elena",LastName:"Campbell"}You can also use the client libraries to create an array ofSTRUCT objects, asseen in the following sample:
C++
// Cloud Spanner STRUCT<> types with named fields are represented by// std::tuple<std::pair<std::string, T>...>, create an alias to make it easier// to follow this code.usingSingerName=std::tuple<std::pair<std::string,std::string>,std::pair<std::string,std::string>>;automake_name=[](std::stringfirst_name,std::stringlast_name){returnstd::make_tuple(std::make_pair("FirstName",std::move(first_name)),std::make_pair("LastName",std::move(last_name)));};std::vector<SingerName>singer_info{make_name("Elena","Campbell"),make_name("Gabriel","Wright"),make_name("Benjamin","Martinez"),};C#
varbandMembers=newList<SpannerStruct>{newSpannerStruct{{"FirstName",SpannerDbType.String,"Elena"},{"LastName",SpannerDbType.String,"Campbell"}},newSpannerStruct{{"FirstName",SpannerDbType.String,"Gabriel"},{"LastName",SpannerDbType.String,"Wright"}},newSpannerStruct{{"FirstName",SpannerDbType.String,"Benjamin"},{"LastName",SpannerDbType.String,"Martinez"}},};Go
varbandMembers=[]nameType{{"Elena","Campbell"},{"Gabriel","Wright"},{"Benjamin","Martinez"},}Java
List<Struct>bandMembers=newArrayList<>();bandMembers.add(Struct.newBuilder().set("FirstName").to("Elena").set("LastName").to("Campbell").build());bandMembers.add(Struct.newBuilder().set("FirstName").to("Gabriel").set("LastName").to("Wright").build());bandMembers.add(Struct.newBuilder().set("FirstName").to("Benjamin").set("LastName").to("Martinez").build());Node.js
constbandMembersType={type:'array',child:nameType,};constbandMembers=[Spanner.struct({FirstName:'Elena',LastName:'Campbell',}),Spanner.struct({FirstName:'Gabriel',LastName:'Wright',}),Spanner.struct({FirstName:'Benjamin',LastName:'Martinez',}),];PHP
$bandMembers = [ (new StructValue) ->add('FirstName', 'Elena') ->add('LastName', 'Campbell'), (new StructValue) ->add('FirstName', 'Gabriel') ->add('LastName', 'Wright'), (new StructValue) ->add('FirstName', 'Benjamin') ->add('LastName', 'Martinez')];Python
band_members=[("Elena","Campbell"),("Gabriel","Wright"),("Benjamin","Martinez"),]Ruby
band_members=[name_type.struct(["Elena","Campbell"]),name_type.struct(["Gabriel","Wright"]),name_type.struct(["Benjamin","Martinez"])]Returning STRUCT objects in SQL query results
A Spanner SQL query can return an array ofSTRUCT objects as acolumn for certain queries. For more information, seeUsing STRUCTS withSELECT.
Using STRUCT objects as bound parameters in SQL queries
You can useSTRUCT objects as bound parameters in a SQL query. For moreinformation about parameters, seeQuery parameters.
Querying data with a STRUCT object
The following sample shows how to bind values in aSTRUCT object to parametersin a SQL query statement, execute the query, and output the results.
C++
voidQueryDataWithStruct(google::cloud::spanner::Clientclient){namespacespanner=::google::cloud::spanner;// Cloud Spanner STRUCT<> types are represented by std::tuple<...>. The// following represents a STRUCT<> with two unnamed STRING fields.usingNameType=std::tuple<std::string,std::string>;autosinger_info=NameType{"Elena","Campbell"};autorows=client.ExecuteQuery(spanner::SqlStatement("SELECT SingerId FROM Singers WHERE (FirstName, LastName) = @name",{{"name", spanner::Value(singer_info)}}));for(auto&row:spanner::StreamOf<std::tuple<std::int64_t>>(rows)){if(!row)throwstd::move(row).status();std::cout <<"SingerId: " <<std::get<0>(*row) <<"\n";}std::cout <<"Query completed for [spanner_query_data_with_struct]\n";}C#
usingGoogle.Cloud.Spanner.Data;usingSystem.Collections.Generic;usingSystem.Threading.Tasks;publicclassQueryDataWithStructAsyncSample{publicasyncTask<List<int>>QueryDataWithStructAsync(stringprojectId,stringinstanceId,stringdatabaseId){varnameStruct=newSpannerStruct{{"FirstName",SpannerDbType.String,"Elena"},{"LastName",SpannerDbType.String,"Campbell"},};stringconnectionString=$"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";varsingerIds=newList<int>();usingvarconnection=newSpannerConnection(connectionString);usingvarcmd=connection.CreateSelectCommand("SELECT SingerId FROM Singers "+"WHERE STRUCT<FirstName STRING, LastName STRING>"+"(FirstName, LastName) = @name");cmd.Parameters.Add("name",nameStruct.GetSpannerDbType(),nameStruct);usingvarreader=awaitcmd.ExecuteReaderAsync();while(awaitreader.ReadAsync()){singerIds.Add(reader.GetFieldValue<int>("SingerId"));}returnsingerIds;}}Go
stmt:=spanner.Statement{SQL:`SELECT SingerId FROM SINGERSWHERE (FirstName, LastName) = @singerinfo`,Params:map[string]interface{}{"singerinfo":singerInfo},}iter:=client.Single().Query(ctx,stmt)deferiter.Stop()for{row,err:=iter.Next()iferr==iterator.Done{returnnil}iferr!=nil{returnerr}varsingerIDint64iferr:=row.Columns(&singerID);err!=nil{returnerr}fmt.Fprintf(w,"%d\n",singerID)}Java
Statements=Statement.newBuilder("SELECT SingerId FROM Singers "+"WHERE STRUCT<FirstName STRING, LastName STRING>(FirstName, LastName) "+"= @name").bind("name").to(name).build();try(ResultSetresultSet=dbClient.singleUse().executeQuery(s)){while(resultSet.next()){System.out.printf("%d\n",resultSet.getLong("SingerId"));}}Node.js
/** * TODO(developer): Uncomment the following lines before running the sample. */// const projectId = 'my-project-id';// const instanceId = 'my-instance';// const databaseId = 'my-database';// Creates a clientconstspanner=newSpanner({projectId:projectId,});// Gets a reference to a Cloud Spanner instance and databaseconstinstance=spanner.instance(instanceId);constdatabase=instance.database(databaseId);constquery={sql:'SELECT SingerId FROM Singers WHERE '+'STRUCT<FirstName STRING, LastName STRING>(FirstName, LastName) = @name',params:{name:nameStruct,},};// Queries rows from the Singers tabletry{const[rows]=awaitdatabase.run(query);rows.forEach(row=>{constjson=row.toJSON();console.log(`SingerId:${json.SingerId}`);});}catch(err){console.error('ERROR:',err);}finally{// Close the database when finished.database.close();}PHP
$results = $database->execute( 'SELECT SingerId FROM Singers ' . 'WHERE STRUCT<FirstName STRING, LastName STRING>' . '(FirstName, LastName) = @name', [ 'parameters' => [ 'name' => $nameValue ], 'types' => [ 'name' => $nameType ] ]);foreach ($results as $row) { printf('SingerId: %s' . PHP_EOL, $row['SingerId']);}Python
spanner_client=spanner.Client()instance=spanner_client.instance(instance_id)database=instance.database(database_id)withdatabase.snapshot()assnapshot:results=snapshot.execute_sql("SELECT SingerId FROM Singers WHERE ""(FirstName, LastName) = @name",params={"name":record_value},param_types={"name":record_type},)forrowinresults:print("SingerId:{}".format(*row))Ruby
# project_id = "Your Google Cloud project ID"# instance_id = "Your Spanner instance ID"# database_id = "Your Spanner database ID"require"google/cloud/spanner"spanner=Google::Cloud::Spanner.newproject:project_idclient=spanner.clientinstance_id,database_idclient.execute("SELECT SingerId FROM Singers WHERE "+"(FirstName, LastName) = @name",params:{name:name_struct}).rows.eachdo|row|putsrow[:SingerId]endQuerying data with an array of STRUCT objects
The following sample shows how to execute a query that uses an array ofSTRUCTobjects. Use theUNNEST operator to flatten an array ofSTRUCT objectsinto rows:
C++
voidQueryDataWithArrayOfStruct(google::cloud::spanner::Clientclient){namespacespanner=::google::cloud::spanner;// Cloud Spanner STRUCT<> types with named fields are represented by// std::tuple<std::pair<std::string, T>...>, create an alias to make it easier// to follow this code.usingSingerName=std::tuple<std::pair<std::string,std::string>,std::pair<std::string,std::string>>;automake_name=[](std::stringfirst_name,std::stringlast_name){returnstd::make_tuple(std::make_pair("FirstName",std::move(first_name)),std::make_pair("LastName",std::move(last_name)));};std::vector<SingerName>singer_info{make_name("Elena","Campbell"),make_name("Gabriel","Wright"),make_name("Benjamin","Martinez"),};autorows=client.ExecuteQuery(spanner::SqlStatement("SELECT SingerId FROM Singers"" WHERE STRUCT<FirstName STRING, LastName STRING>(FirstName, LastName)"" IN UNNEST(@names)",{{"names", spanner::Value(singer_info)}}));for(auto&row:spanner::StreamOf<std::tuple<std::int64_t>>(rows)){if(!row)throwstd::move(row).status();std::cout <<"SingerId: " <<std::get<0>(*row) <<"\n";}std::cout <<"Query completed for" <<" [spanner_query_data_with_array_of_struct]\n";}C#
usingGoogle.Cloud.Spanner.Data;usingSystem.Collections.Generic;usingSystem.Threading.Tasks;publicclassQueryDataWithArrayOfStructAsyncSample{publicasyncTask<List<int>>QueryDataWithArrayOfStructAsync(stringprojectId,stringinstanceId,stringdatabaseId){varnameType=newSpannerStruct{{"FirstName",SpannerDbType.String,null},{"LastName",SpannerDbType.String,null}};varbandMembers=newList<SpannerStruct>{newSpannerStruct{{"FirstName",SpannerDbType.String,"Elena"},{"LastName",SpannerDbType.String,"Campbell"}},newSpannerStruct{{"FirstName",SpannerDbType.String,"Gabriel"},{"LastName",SpannerDbType.String,"Wright"}},newSpannerStruct{{"FirstName",SpannerDbType.String,"Benjamin"},{"LastName",SpannerDbType.String,"Martinez"}},};varsingerIds=newList<int>();stringconnectionString=$"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";usingvarconnection=newSpannerConnection(connectionString);usingvarcmd=connection.CreateSelectCommand("SELECT SingerId FROM Singers WHERE STRUCT<FirstName STRING, LastName STRING> "+"(FirstName, LastName) IN UNNEST(@names)");cmd.Parameters.Add("names",SpannerDbType.ArrayOf(nameType.GetSpannerDbType()),bandMembers);usingvarreader=awaitcmd.ExecuteReaderAsync();while(awaitreader.ReadAsync()){singerIds.Add(reader.GetFieldValue<int>("SingerId"));}returnsingerIds;}}Go
stmt:=spanner.Statement{SQL:`SELECT SingerId FROM SINGERSWHERE STRUCT<FirstName STRING, LastName STRING>(FirstName, LastName)IN UNNEST(@names)`,Params:map[string]interface{}{"names":bandMembers},}iter:=client.Single().Query(ctx,stmt)deferiter.Stop()for{row,err:=iter.Next()iferr==iterator.Done{returnnil}iferr!=nil{returnerr}varsingerIDint64iferr:=row.Columns(&singerID);err!=nil{returnerr}fmt.Fprintf(w,"%d\n",singerID)}Java
Statements=Statement.newBuilder("SELECT SingerId FROM Singers WHERE "+"STRUCT<FirstName STRING, LastName STRING>(FirstName, LastName) "+"IN UNNEST(@names) "+"ORDER BY SingerId DESC").bind("names").toStructArray(nameType,bandMembers).build();try(ResultSetresultSet=dbClient.singleUse().executeQuery(s)){while(resultSet.next()){System.out.printf("%d\n",resultSet.getLong("SingerId"));}}Node.js
constquery={sql:'SELECT SingerId FROM Singers '+'WHERE STRUCT<FirstName STRING, LastName STRING>(FirstName, LastName) '+'IN UNNEST(@names) '+'ORDER BY SingerId',params:{names:bandMembers,},types:{names:bandMembersType,},};// Queries rows from the Singers tabletry{const[rows]=awaitdatabase.run(query);rows.forEach(row=>{constjson=row.toJSON();console.log(`SingerId:${json.SingerId}`);});}catch(err){console.error('ERROR:',err);}finally{// Close the database when finished.database.close();}PHP
$results = $database->execute( 'SELECT SingerId FROM Singers ' . 'WHERE STRUCT<FirstName STRING, LastName STRING>(FirstName, LastName) ' . 'IN UNNEST(@names)', [ 'parameters' => [ 'names' => $bandMembers ], 'types' => [ 'names' => $nameType ] ]);foreach ($results as $row) { printf('SingerId: %s' . PHP_EOL, $row['SingerId']);}Python
spanner_client=spanner.Client()instance=spanner_client.instance(instance_id)database=instance.database(database_id)withdatabase.snapshot()assnapshot:results=snapshot.execute_sql("SELECT SingerId FROM Singers WHERE ""STRUCT<FirstName STRING, LastName STRING>""(FirstName, LastName) IN UNNEST(@names)",params={"names":band_members},param_types={"names":param_types.Array(name_type)},)forrowinresults:print("SingerId:{}".format(*row))Ruby
client.execute("SELECT SingerId FROM Singers WHERE "+"STRUCT<FirstName STRING, LastName STRING>(FirstName, LastName) IN UNNEST(@names)",params:{names:band_members}).rows.eachdo|row|putsrow[:SingerId]endModifying data with DML
The following code example uses aSTRUCT with bound parameters and DataManipulation Language (DML) to update a single value in rows that match theWHERE clause condition. For rows where theFirstName isTimothy and theLastName isCampbell, theLastName is updated toGrant.
C++
voidDmlStructs(google::cloud::spanner::Clientclient){namespacespanner=::google::cloud::spanner;std::int64_trows_modified=0;autocommit_result=client.Commit([&client,&rows_modified](spanner::Transactionconst&txn)->google::cloud::StatusOr<spanner::Mutations>{autosinger_info=std::make_tuple("Marc","Richards");autosql=spanner::SqlStatement("UPDATE Singers SET FirstName = 'Keith' WHERE ""STRUCT<FirstName String, LastName String>(FirstName, LastName) ""= @name",{{"name", spanner::Value(std::move(singer_info))}});autodml_result=client.ExecuteDml(txn,std::move(sql));if(!dml_result)returnstd::move(dml_result).status();rows_modified=dml_result->RowsModified();returnspanner::Mutations{};});if(!commit_result)throwstd::move(commit_result).status();std::cout <<rows_modified <<" update was successful [spanner_dml_structs]\n";}C#
usingGoogle.Cloud.Spanner.Data;usingSystem;usingSystem.Threading.Tasks;publicclassUpdateUsingDmlWithStructCoreAsyncSample{publicasyncTask<int>UpdateUsingDmlWithStructCoreAsync(stringprojectId,stringinstanceId,stringdatabaseId){varnameStruct=newSpannerStruct{{"FirstName",SpannerDbType.String,"Timothy"},{"LastName",SpannerDbType.String,"Campbell"}};stringconnectionString=$"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";usingvarconnection=newSpannerConnection(connectionString);awaitconnection.OpenAsync();usingvarcmd=connection.CreateDmlCommand("UPDATE Singers SET LastName = 'Grant' WHERE STRUCT<FirstName STRING, LastName STRING>(FirstName, LastName) = @name");cmd.Parameters.Add("name",nameStruct.GetSpannerDbType(),nameStruct);introwCount=awaitcmd.ExecuteNonQueryAsync();Console.WriteLine($"{rowCount} row(s) updated...");returnrowCount;}}Go
import("context""fmt""io""cloud.google.com/go/spanner")funcupdateUsingDMLStruct(wio.Writer,dbstring)error{ctx:=context.Background()client,err:=spanner.NewClient(ctx,db)iferr!=nil{returnerr}deferclient.Close()_,err=client.ReadWriteTransaction(ctx,func(ctxcontext.Context,txn*spanner.ReadWriteTransaction)error{typenamestruct{FirstNamestringLastNamestring}varsingerInfo=name{"Timothy","Campbell"}stmt:=spanner.Statement{SQL:`Update Singers Set LastName = 'Grant'WHERE STRUCT<FirstName String, LastName String>(Firstname, LastName) = @name`,Params:map[string]interface{}{"name":singerInfo},}rowCount,err:=txn.Update(ctx,stmt)iferr!=nil{returnerr}fmt.Fprintf(w,"%d record(s) inserted.\n",rowCount)returnnil})returnerr}Java
staticvoidupdateUsingDmlWithStruct(DatabaseClientdbClient){Structname=Struct.newBuilder().set("FirstName").to("Timothy").set("LastName").to("Campbell").build();Statements=Statement.newBuilder("UPDATE Singers SET LastName = 'Grant' "+"WHERE STRUCT<FirstName STRING, LastName STRING>(FirstName, LastName) "+"= @name").bind("name").to(name).build();dbClient.readWriteTransaction().run(transaction->{longrowCount=transaction.executeUpdate(s);System.out.printf("%d record updated.\n",rowCount);returnnull;});}Node.js
// Imports the Google Cloud client libraryconst{Spanner}=require('@google-cloud/spanner');constnameStruct=Spanner.struct({FirstName:'Timothy',LastName:'Campbell',});/** * TODO(developer): Uncomment the following lines before running the sample. */// const projectId = 'my-project-id';// const instanceId = 'my-instance';// const databaseId = 'my-database';// Creates a clientconstspanner=newSpanner({projectId:projectId,});// Gets a reference to a Cloud Spanner instance and databaseconstinstance=spanner.instance(instanceId);constdatabase=instance.database(databaseId);database.runTransaction(async(err,transaction)=>{if(err){console.error(err);return;}try{const[rowCount]=awaittransaction.runUpdate({sql:`UPDATE Singers SET LastName = 'Grant' WHERE STRUCT<FirstName STRING, LastName STRING>(FirstName, LastName) = @name`,params:{name:nameStruct,},});console.log(`Successfully updated${rowCount} record.`);awaittransaction.commit();}catch(err){console.error('ERROR:',err);}finally{// Close the database when finished.database.close();}});PHP
use Google\Cloud\Spanner\SpannerClient;use Google\Cloud\Spanner\Database;use Google\Cloud\Spanner\Transaction;use Google\Cloud\Spanner\StructType;use Google\Cloud\Spanner\StructValue;/** * Update data with a DML statement using Structs. * * The database and table must already exist and can be created using * `create_database`. * Example: * ``` * insert_data($instanceId, $databaseId); * ``` * * @param string $instanceId The Spanner instance ID. * @param string $databaseId The Spanner database ID. */function update_data_with_dml_structs(string $instanceId, string $databaseId): void{ $spanner = new SpannerClient(); $instance = $spanner->instance($instanceId); $database = $instance->database($databaseId); $database->runTransaction(function (Transaction $t) { $nameValue = (new StructValue) ->add('FirstName', 'Timothy') ->add('LastName', 'Campbell'); $nameType = (new StructType) ->add('FirstName', Database::TYPE_STRING) ->add('LastName', Database::TYPE_STRING); $rowCount = $t->executeUpdate( "UPDATE Singers SET LastName = 'Grant' " . 'WHERE STRUCT<FirstName STRING, LastName STRING>(FirstName, LastName) ' . '= @name', [ 'parameters' => [ 'name' => $nameValue ], 'types' => [ 'name' => $nameType ] ]); $t->commit(); printf('Updated %d row(s).' . PHP_EOL, $rowCount); });}Python
# instance_id = "your-spanner-instance"# database_id = "your-spanner-db-id"spanner_client=spanner.Client()instance=spanner_client.instance(instance_id)database=instance.database(database_id)record_type=param_types.Struct([param_types.StructField("FirstName",param_types.STRING),param_types.StructField("LastName",param_types.STRING),])record_value=("Timothy","Campbell")defwrite_with_struct(transaction):row_ct=transaction.execute_update("UPDATE Singers SET LastName = 'Grant' ""WHERE STRUCT<FirstName STRING, LastName STRING>""(FirstName, LastName) = @name",params={"name":record_value},param_types={"name":record_type},)print("{} record(s) updated.".format(row_ct))database.run_in_transaction(write_with_struct)Ruby
# project_id = "Your Google Cloud project ID"# instance_id = "Your Spanner instance ID"# database_id = "Your Spanner database ID"require"google/cloud/spanner"spanner=Google::Cloud::Spanner.newproject:project_idclient=spanner.clientinstance_id,database_idrow_count=0name_struct={FirstName:"Timothy",LastName:"Campbell"}client.transactiondo|transaction|row_count=transaction.execute_update("UPDATE Singers SET LastName = 'Grant' WHERE STRUCT<FirstName STRING, LastName STRING>(FirstName, LastName) = @name",params:{name:name_struct})endputs"#{row_count} record updated."Accessing STRUCT field values
You can access fields inside aSTRUCT object by name.
C++
voidFieldAccessOnStructParameters(google::cloud::spanner::Clientclient){namespacespanner=::google::cloud::spanner;// Cloud Spanner STRUCT<> with named fields is represented as// tuple<pair<string, T>...>. Create a type alias for this example:usingSingerName=std::tuple<std::pair<std::string,std::string>,std::pair<std::string,std::string>>;SingerNamename({"FirstName","Elena"},{"LastName","Campbell"});autorows=client.ExecuteQuery(spanner::SqlStatement("SELECT SingerId FROM Singers WHERE FirstName = @name.FirstName",{{"name", spanner::Value(name)}}));for(auto&row:spanner::StreamOf<std::tuple<std::int64_t>>(rows)){if(!row)throwstd::move(row).status();std::cout <<"SingerId: " <<std::get<0>(*row) <<"\n";}std::cout <<"Query completed for" <<" [spanner_field_access_on_struct_parameters]\n";}C#
usingGoogle.Cloud.Spanner.Data;usingSystem.Collections.Generic;usingSystem.Threading.Tasks;publicclassQueryDataWithStructFieldAsyncSample{publicasyncTask<List<int>>QueryDataWithStructFieldAsync(stringprojectId,stringinstanceId,stringdatabaseId){stringconnectionString=$"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";varstructParam=newSpannerStruct{{"FirstName",SpannerDbType.String,"Elena"},{"LastName",SpannerDbType.String,"Campbell"},};varsingerIds=newList<int>();usingvarconnection=newSpannerConnection(connectionString);usingvarcmd=connection.CreateSelectCommand("SELECT SingerId FROM Singers WHERE FirstName = @name.FirstName");cmd.Parameters.Add("name",structParam.GetSpannerDbType(),structParam);usingvarreader=awaitcmd.ExecuteReaderAsync();while(awaitreader.ReadAsync()){singerIds.Add(reader.GetFieldValue<int>("SingerId"));}returnsingerIds;}}Go
import("context""fmt""io""cloud.google.com/go/spanner""google.golang.org/api/iterator")funcqueryWithStructField(wio.Writer,dbstring)error{ctx:=context.Background()client,err:=spanner.NewClient(ctx,db)iferr!=nil{returnerr}deferclient.Close()typestructParamstruct{FirstNamestringLastNamestring}varsingerInfo=structParam{"Elena","Campbell"}stmt:=spanner.Statement{SQL:`SELECT SingerId FROM SINGERSWHERE FirstName = @name.FirstName`,Params:map[string]interface{}{"name":singerInfo},}iter:=client.Single().Query(ctx,stmt)deferiter.Stop()for{row,err:=iter.Next()iferr==iterator.Done{returnnil}iferr!=nil{returnerr}varsingerIDint64iferr:=row.Columns(&singerID);err!=nil{returnerr}fmt.Fprintf(w,"%d\n",singerID)}}Java
staticvoidqueryStructField(DatabaseClientdbClient){Statements=Statement.newBuilder("SELECT SingerId FROM Singers WHERE FirstName = @name.FirstName").bind("name").to(Struct.newBuilder().set("FirstName").to("Elena").set("LastName").to("Campbell").build()).build();try(ResultSetresultSet=dbClient.singleUse().executeQuery(s)){while(resultSet.next()){System.out.printf("%d\n",resultSet.getLong("SingerId"));}}}Node.js
// Imports the Google Cloud client libraryconst{Spanner}=require('@google-cloud/spanner');/** * TODO(developer): Uncomment the following lines before running the sample. */// const projectId = 'my-project-id';// const instanceId = 'my-instance';// const databaseId = 'my-database';// Creates a clientconstspanner=newSpanner({projectId:projectId,});// Gets a reference to a Cloud Spanner instance and databaseconstinstance=spanner.instance(instanceId);constdatabase=instance.database(databaseId);constnameStruct=Spanner.struct({FirstName:'Elena',LastName:'Campbell',});constquery={sql:'SELECT SingerId FROM Singers WHERE FirstName = @name.FirstName',params:{name:nameStruct,},};// Queries rows from the Singers tabletry{const[rows]=awaitdatabase.run(query);rows.forEach(row=>{constjson=row.toJSON();console.log(`SingerId:${json.SingerId}`);});}catch(err){console.error('ERROR:',err);}finally{// Close the database when finished.database.close();}PHP
use Google\Cloud\Spanner\SpannerClient;use Google\Cloud\Spanner\Database;use Google\Cloud\Spanner\StructType;/** * Queries sample data from the database using a struct field value. * Example: * ``` * query_data_with_struct_field($instanceId, $databaseId); * ``` * * @param string $instanceId The Spanner instance ID. * @param string $databaseId The Spanner database ID. */function query_data_with_struct_field(string $instanceId, string $databaseId): void{ $spanner = new SpannerClient(); $instance = $spanner->instance($instanceId); $database = $instance->database($databaseId); $nameType = (new StructType) ->add('FirstName', Database::TYPE_STRING) ->add('LastName', Database::TYPE_STRING); $results = $database->execute( 'SELECT SingerId FROM Singers WHERE FirstName = @name.FirstName', [ 'parameters' => [ 'name' => [ 'FirstName' => 'Elena', 'LastName' => 'Campbell' ] ], 'types' => [ 'name' => $nameType ] ] ); foreach ($results as $row) { printf('SingerId: %s' . PHP_EOL, $row['SingerId']); }}Python
defquery_struct_field(instance_id,database_id):"""Query a table using field access on a STRUCT parameter."""spanner_client=spanner.Client()instance=spanner_client.instance(instance_id)database=instance.database(database_id)name_type=param_types.Struct([param_types.StructField("FirstName",param_types.STRING),param_types.StructField("LastName",param_types.STRING),])withdatabase.snapshot()assnapshot:results=snapshot.execute_sql("SELECT SingerId FROM Singers ""WHERE FirstName = @name.FirstName",params={"name":("Elena","Campbell")},param_types={"name":name_type},)forrowinresults:print("SingerId:{}".format(*row))Ruby
# project_id = "Your Google Cloud project ID"# instance_id = "Your Spanner instance ID"# database_id = "Your Spanner database ID"require"google/cloud/spanner"spanner=Google::Cloud::Spanner.newproject:project_idclient=spanner.clientinstance_id,database_idname_struct={FirstName:"Elena",LastName:"Campbell"}client.execute("SELECT SingerId FROM Singers WHERE FirstName = @name.FirstName",params:{name:name_struct}).rows.eachdo|row|putsrow[:SingerId]endYou can even have fields ofSTRUCT orARRAY<STRUCT> type insideSTRUCTvalues and access them similarly:
C++
voidFieldAccessOnNestedStruct(google::cloud::spanner::Clientclient){namespacespanner=::google::cloud::spanner;// Cloud Spanner STRUCT<> with named fields is represented as// tuple<pair<string, T>...>. Create a type alias for this example:usingSingerFullName=std::tuple<std::pair<std::string,std::string>,std::pair<std::string,std::string>>;automake_name=[](std::stringfname,std::stringlname){returnSingerFullName({"FirstName",std::move(fname)},{"LastName",std::move(lname)});};usingSongInfo=std::tuple<std::pair<std::string,std::string>,std::pair<std::string,std::vector<SingerFullName>>>;autosonginfo=SongInfo({"SongName","Imagination"},{"ArtistNames",{make_name("Elena","Campbell"),make_name("Hannah","Harris")}});autorows=client.ExecuteQuery(spanner::SqlStatement("SELECT SingerId, @songinfo.SongName FROM Singers"" WHERE STRUCT<FirstName STRING, LastName STRING>(FirstName, LastName)"" IN UNNEST(@songinfo.ArtistNames)",{{"songinfo", spanner::Value(songinfo)}}));usingRowType=std::tuple<std::int64_t,std::string>;for(auto&row:spanner::StreamOf<RowType>(rows)){if(!row)throwstd::move(row).status();std::cout <<"SingerId: " <<std::get<0>(*row) <<" SongName: " <<std::get<1>(*row) <<"\n";}std::cout <<"Query completed for [spanner_field_access_on_nested_struct]\n";}C#
usingGoogle.Cloud.Spanner.Data;usingSystem;usingSystem.Collections.Generic;usingSystem.Threading.Tasks;publicclassQueryDataWithNestedStructFieldAsyncSample{publicasyncTask<List<int>>QueryDataWithNestedStructFieldAsync(stringprojectId,stringinstanceId,stringdatabaseId){stringconnectionString=$"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";SpannerStructname1=newSpannerStruct{{"FirstName",SpannerDbType.String,"Elena"},{"LastName",SpannerDbType.String,"Campbell"}};SpannerStructname2=newSpannerStruct{{"FirstName",SpannerDbType.String,"Hannah"},{"LastName",SpannerDbType.String,"Harris"}};SpannerStructsongInfo=newSpannerStruct{{"song_name",SpannerDbType.String,"Imagination"},{"artistNames",SpannerDbType.ArrayOf(name1.GetSpannerDbType()),new[]{name1,name2}}};varsingerIds=newList<int>();usingvarconnection=newSpannerConnection(connectionString);usingvarcmd=connection.CreateSelectCommand("SELECT SingerId, @song_info.song_name "+"FROM Singers WHERE STRUCT<FirstName STRING, LastName STRING>(FirstName, LastName) "+"IN UNNEST(@song_info.artistNames)");cmd.Parameters.Add("song_info",songInfo.GetSpannerDbType(),songInfo);usingvarreader=awaitcmd.ExecuteReaderAsync();while(awaitreader.ReadAsync()){varsingerId=reader.GetFieldValue<int>("SingerId");singerIds.Add(singerId);Console.WriteLine($"SingerId: {singerId}");Console.WriteLine($"Song Name: {reader.GetFieldValue<string>(1)}");}returnsingerIds;}}Go
import("context""fmt""io""cloud.google.com/go/spanner""google.golang.org/api/iterator")funcqueryWithNestedStructField(wio.Writer,dbstring)error{ctx:=context.Background()client,err:=spanner.NewClient(ctx,db)iferr!=nil{returnerr}deferclient.Close()typenameTypestruct{FirstNamestringLastNamestring}typesongInfoStructstruct{SongNamestringArtistNames[]nameType}varsongInfo=songInfoStruct{SongName:"Imagination",ArtistNames:[]nameType{{FirstName:"Elena",LastName:"Campbell"},{FirstName:"Hannah",LastName:"Harris"},},}stmt:=spanner.Statement{SQL:`SELECT SingerId, @songinfo.SongName FROM SingersWHERE STRUCT<FirstName STRING, LastName STRING>(FirstName, LastName)IN UNNEST(@songinfo.ArtistNames)`,Params:map[string]interface{}{"songinfo":songInfo},}iter:=client.Single().Query(ctx,stmt)deferiter.Stop()for{row,err:=iter.Next()iferr==iterator.Done{returnnil}iferr!=nil{returnerr}varsingerIDint64varsongNamestringiferr:=row.Columns(&singerID,&songName);err!=nil{returnerr}fmt.Fprintf(w,"%d %s\n",singerID,songName)}}Java
staticvoidqueryNestedStructField(DatabaseClientdbClient){TypenameType=Type.struct(Arrays.asList(StructField.of("FirstName",Type.string()),StructField.of("LastName",Type.string())));StructsongInfo=Struct.newBuilder().set("song_name").to("Imagination").set("artistNames").toStructArray(nameType,Arrays.asList(Struct.newBuilder().set("FirstName").to("Elena").set("LastName").to("Campbell").build(),Struct.newBuilder().set("FirstName").to("Hannah").set("LastName").to("Harris").build())).build();Statements=Statement.newBuilder("SELECT SingerId, @song_info.song_name "+"FROM Singers WHERE "+"STRUCT<FirstName STRING, LastName STRING>(FirstName, LastName) "+"IN UNNEST(@song_info.artistNames)").bind("song_info").to(songInfo).build();try(ResultSetresultSet=dbClient.singleUse().executeQuery(s)){while(resultSet.next()){System.out.printf("%d %s\n",resultSet.getLong("SingerId"),resultSet.getString(1));}}}Node.js
// Imports the Google Cloud client libraryconst{Spanner}=require('@google-cloud/spanner');/** * TODO(developer): Uncomment the following lines before running the sample. */// const projectId = 'my-project-id';// const instanceId = 'my-instance';// const databaseId = 'my-database';// Creates a clientconstspanner=newSpanner({projectId:projectId,});// Gets a reference to a Cloud Spanner instance and databaseconstinstance=spanner.instance(instanceId);constdatabase=instance.database(databaseId);constnameType={type:'struct',fields:[{name:'FirstName',type:'string',},{name:'LastName',type:'string',},],};// Creates Song info STRUCT with a nested ArtistNames arrayconstsongInfoType={type:'struct',fields:[{name:'SongName',type:'string',},{name:'ArtistNames',type:'array',child:nameType,},],};constsongInfoStruct=Spanner.struct({SongName:'Imagination',ArtistNames:[Spanner.struct({FirstName:'Elena',LastName:'Campbell'}),Spanner.struct({FirstName:'Hannah',LastName:'Harris'}),],});constquery={sql:'SELECT SingerId, @songInfo.SongName FROM Singers '+'WHERE STRUCT<FirstName STRING, LastName STRING>(FirstName, LastName) '+'IN UNNEST(@songInfo.ArtistNames)',params:{songInfo:songInfoStruct,},types:{songInfo:songInfoType,},};// Queries rows from the Singers tabletry{const[rows]=awaitdatabase.run(query);rows.forEach(row=>{constjson=row.toJSON();console.log(`SingerId:${json.SingerId}, SongName:${json.SongName}`);});}catch(err){console.error('ERROR:',err);}finally{// Close the database when finished.database.close();}PHP
use Google\Cloud\Spanner\SpannerClient;use Google\Cloud\Spanner\Database;use Google\Cloud\Spanner\StructType;use Google\Cloud\Spanner\StructValue;use Google\Cloud\Spanner\ArrayType;/** * Queries sample data from the database using a nested struct field value. * Example: * ``` * query_data_with_nested_struct_field($instanceId, $databaseId); * ``` * * @param string $instanceId The Spanner instance ID. * @param string $databaseId The Spanner database ID. */function query_data_with_nested_struct_field(string $instanceId, string $databaseId): void{ $spanner = new SpannerClient(); $instance = $spanner->instance($instanceId); $database = $instance->database($databaseId); $nameType = new ArrayType( (new StructType) ->add('FirstName', Database::TYPE_STRING) ->add('LastName', Database::TYPE_STRING) ); $songInfoType = (new StructType) ->add('SongName', Database::TYPE_STRING) ->add('ArtistNames', $nameType); $nameStructValue1 = (new StructValue) ->add('FirstName', 'Elena') ->add('LastName', 'Campbell'); $nameStructValue2 = (new StructValue) ->add('FirstName', 'Hannah') ->add('LastName', 'Harris'); $songInfoValues = (new StructValue) ->add('SongName', 'Imagination') ->add('ArtistNames', [$nameStructValue1, $nameStructValue2]); $results = $database->execute( 'SELECT SingerId, @song_info.SongName FROM Singers ' . 'WHERE STRUCT<FirstName STRING, LastName STRING>(FirstName, LastName) ' . 'IN UNNEST(@song_info.ArtistNames)', [ 'parameters' => [ 'song_info' => $songInfoValues ], 'types' => [ 'song_info' => $songInfoType ] ] ); foreach ($results as $row) { printf('SingerId: %s SongName: %s' . PHP_EOL, $row['SingerId'], $row['SongName']); }}Python
defquery_nested_struct_field(instance_id,database_id):"""Query a table using nested field access on a STRUCT parameter."""spanner_client=spanner.Client()instance=spanner_client.instance(instance_id)database=instance.database(database_id)song_info_type=param_types.Struct([param_types.StructField("SongName",param_types.STRING),param_types.StructField("ArtistNames",param_types.Array(param_types.Struct([param_types.StructField("FirstName",param_types.STRING),param_types.StructField("LastName",param_types.STRING),])),),])song_info=("Imagination",[("Elena","Campbell"),("Hannah","Harris")])withdatabase.snapshot()assnapshot:results=snapshot.execute_sql("SELECT SingerId, @song_info.SongName ""FROM Singers WHERE ""STRUCT<FirstName STRING, LastName STRING>""(FirstName, LastName) ""IN UNNEST(@song_info.ArtistNames)",params={"song_info":song_info},param_types={"song_info":song_info_type},)forrowinresults:print("SingerId:{} SongName:{}".format(*row))Ruby
# project_id = "Your Google Cloud project ID"# instance_id = "Your Spanner instance ID"# database_id = "Your Spanner database ID"require"google/cloud/spanner"spanner=Google::Cloud::Spanner.newproject:project_idclient=spanner.clientinstance_id,database_idname_type=client.fieldsFirstName::STRING,LastName::STRINGsong_info_struct={SongName:"Imagination",ArtistNames:[name_type.struct(["Elena","Campbell"]),name_type.struct(["Hannah","Harris"])]}client.execute("SELECT SingerId, @song_info.SongName "\"FROM Singers WHERE STRUCT<FirstName STRING, LastName STRING>(FirstName, LastName) "\"IN UNNEST(@song_info.ArtistNames)",params:{song_info:song_info_struct}).rows.eachdo|row|puts(row[:SingerId]),(row[:SongName])endExcept 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.