### Install Dependencies Source: https://github.com/googleapis/nodejs-spanner/blob/main/CONTRIBUTING.md Run this command to install project dependencies before running tests or making code changes. ```bash npm install ``` -------------------------------- ### Run benchwrapper Source: https://github.com/googleapis/nodejs-spanner/blob/main/bin/README.md Follow these steps to install dependencies, set the Spanner emulator host, and run the benchwrapper server on a specified port. ```bash cd nodejs-spanner npm install export SPANNER_EMULATOR_HOST=localhost:8080 npm run benchwrapper -- --port 8081 ``` -------------------------------- ### Install @google-cloud/spanner Source: https://context7.com/googleapis/nodejs-spanner/llms.txt Install the official Node.js client library for Google Cloud Spanner using npm. ```bash npm install @google-cloud/spanner ``` -------------------------------- ### Initialize Spanner Client and Run Query Source: https://github.com/googleapis/nodejs-spanner/blob/main/README.md Initialize the Spanner client, get a reference to an instance and database, and execute a simple SQL query. Ensure you have your project ID, instance ID, and database ID configured. ```javascript // Imports the Google Cloud client library const {Spanner} = require('@google-cloud/spanner'); // Creates a client const spanner = new Spanner({projectId}); // Gets a reference to a Cloud Spanner instance and database const instance = spanner.instance(instanceId); const database = instance.database(databaseId); // The query to execute const query = { sql: 'SELECT 1', }; // Execute a simple SQL statement const [rows] = await database.run(query); console.log(`Query: ${rows.length} found.`); ows.forEach(row => console.log(row)); ``` -------------------------------- ### Generate Singer Proto Files Source: https://github.com/googleapis/nodejs-spanner/blob/main/samples/resource/README.md Installs the protobuf CLI, navigates to the samples directory, and generates JavaScript and TypeScript definition files from a proto definition. It also generates a descriptor set file. ```shell npm install -g protobufjs-cli cd samples/resource pbjs -t static-module -w commonjs -o singer.js singer.proto pbts -o singer.d.ts singer.js protoc --proto_path=. --include_imports --descriptor_set_out=descriptors.pb singer.proto ``` -------------------------------- ### Get a Database Reference Source: https://context7.com/googleapis/nodejs-spanner/llms.txt Obtain a `Database` object. The `database.get()` method can create the database if `autoCreate` is set. Remember to close the database reference when done to return sessions to the pool. ```javascript const {Spanner} = require('@google-cloud/spanner'); const spanner = new Spanner({projectId: 'my-project'}); const instance = spanner.instance('my-instance'); const database = instance.database('my-database'); // Check if the database exists const [exists] = await database.exists(); console.log('Exists:', exists); // Get or create const [db] = await database.get({autoCreate: true}); console.log('Database name:', db.formattedName_); await database.close(); // returns sessions to the pool ``` -------------------------------- ### Get DatabaseAdmin and InstanceAdmin Clients Source: https://context7.com/googleapis/nodejs-spanner/llms.txt Obtain shared, managed GAPIC client objects for direct access to the DatabaseAdmin and InstanceAdmin APIs. Do not close these clients manually; closing the parent `Spanner` instance is sufficient. ```javascript const {Spanner} = require('@google-cloud/spanner'); const spanner = new Spanner({projectId: 'my-project'}); const databaseAdminClient = spanner.getDatabaseAdminClient(); const instanceAdminClient = spanner.getInstanceAdminClient(); // Create a database using the admin client directly const [operation] = await databaseAdminClient.createDatabase({ createStatement: 'CREATE DATABASE `my-database`', extraStatements: [ `CREATE TABLE Singers ( SingerId INT64 NOT NULL, FirstName STRING(1024), LastName STRING(1024) ) PRIMARY KEY (SingerId)`, `CREATE TABLE Albums ( SingerId INT64 NOT NULL, AlbumId INT64 NOT NULL, AlbumTitle STRING(MAX) ) PRIMARY KEY (SingerId, AlbumId), INTERLEAVE IN PARENT Singers ON DELETE CASCADE`, ], parent: databaseAdminClient.instancePath('my-project', 'my-instance'), }); await operation.promise(); console.log('Database created.'); spanner.close(); ``` -------------------------------- ### Add OpenTelemetry Dependencies Source: https://github.com/googleapis/nodejs-spanner/blob/main/OBSERVABILITY.md Install the necessary OpenTelemetry packages for SDKs, Cloud Trace exporter, and gRPC instrumentation. ```javascript // Required packages for OpenTelemetry SDKs "@opentelemetry/sdk-trace-base": "^1.26.0", "@opentelemetry/sdk-trace-node": "^1.26.0", // Package to use Google Cloud Trace exporter "@google-cloud/opentelemetry-cloud-trace-exporter": "^2.4.1", // Packages to enable gRPC instrumentation "@opentelemetry/instrumentation": "^0.53.0", "@opentelemetry/instrumentation-grpc": "^0.53.0" ``` -------------------------------- ### Generate Singer JS and TS Files from Proto Source: https://github.com/googleapis/nodejs-spanner/blob/main/test/data/README.md Install protobufjs-cli globally, navigate to the test data directory, and then use pbjs to generate static JavaScript modules and pbts to create TypeScript definition files from a proto file. Finally, use protoc to create a descriptor set file. ```shell npm install -g protobufjs-cli cd test/data pbjs -t static-module -w commonjs -o singer.js singer.proto pbts -o singer.d.ts singer.js protoc --proto_path=. --include_imports --descriptor_set_out=descriptors.pb singer.proto ``` -------------------------------- ### Get Spanner Instance Reference and Metadata Source: https://context7.com/googleapis/nodejs-spanner/llms.txt Obtain a reference to a Spanner instance and retrieve its metadata. This does not make an API call until metadata is explicitly fetched. Also demonstrates listing databases and deleting the instance. ```javascript const {Spanner} = require('@google-cloud/spanner'); const spanner = new Spanner({projectId: 'my-project'}); const instance = spanner.instance('my-instance'); // Get instance metadata const [metadata] = await instance.get(); console.log('Instance config:', metadata.config); console.log('Node count:', metadata.nodeCount); // List databases on the instance const [databases] = await instance.getDatabases(); databases.forEach(db => console.log('Database:', db.formattedName_)); // Delete the instance await instance.delete(); ``` -------------------------------- ### Get Spanner Database Operations Source: https://github.com/googleapis/nodejs-spanner/blob/main/samples/README.md Retrieves the operations related to a Spanner database. ```javascript node samples/backups-get-database-operations.js ``` -------------------------------- ### Run Sample Integration Tests Source: https://github.com/googleapis/nodejs-spanner/blob/main/CONTRIBUTING.md Run integration tests specifically for the sample code. ```bash # Run sample integration tests. npm run samples-test ``` -------------------------------- ### Get Spanner Backup Operations Source: https://github.com/googleapis/nodejs-spanner/blob/main/samples/README.md Retrieves the operations related to Spanner backups. ```javascript node samples/backups-get-operations.js ``` -------------------------------- ### Create Spanner Client with Options Source: https://context7.com/googleapis/nodejs-spanner/llms.txt Instantiate the Spanner client using Application Default Credentials, explicit service account keys, or the emulator. Advanced options for routing and metrics are also shown. ```javascript const {Spanner} = require('@google-cloud/spanner'); // Using Application Default Credentials (ADC) const spanner = new Spanner({projectId: 'my-project'}); // Explicit service-account key file const spannerExplicit = new Spanner({ projectId: 'my-project', keyFilename: '/path/to/service-account.json', }); // Connecting to the Spanner emulator process.env.SPANNER_EMULATOR_HOST = 'localhost:9010'; const spannerEmulator = new Spanner({projectId: 'test-project'}); // With directed reads, leader-aware routing disabled, and built-in metrics off const spannerAdvanced = new Spanner({ projectId: 'my-project', routeToLeaderEnabled: false, disableBuiltInMetrics: true, directedReadOptions: { includeReplicas: { replicaSelections: [{location: 'us-east1', type: 'READ_ONLY'}], autoFailoverDisabled: true, }, }, }); // Always close the client when done to release gRPC resources spanner.close(); ``` -------------------------------- ### Run All System Tests Source: https://github.com/googleapis/nodejs-spanner/blob/main/CONTRIBUTING.md Execute all system tests to ensure the library functions correctly in a production-like environment. ```bash # Run all system tests. npm run system-test ``` -------------------------------- ### Get Snapshot for Read-Only Transactions Source: https://context7.com/googleapis/nodejs-spanner/llms.txt Use `getSnapshot` to obtain a `Snapshot` object for consistent, highly scalable read-only transactions. This method is ideal for read-heavy workloads where data consistency at a specific point in time is required. ```javascript const {Spanner} = require('@google-cloud/spanner'); const spanner = new Spanner({projectId: 'my-project'}); const database = spanner.instance('my-instance').database('my-database'); database.getSnapshot(async (err, snapshot) => { if (err) { console.error(err); return; } try { // Both reads below see the exact same database state const [albums] = await snapshot.run('SELECT AlbumId, AlbumTitle FROM Albums'); albums.forEach(row => console.log(row.toJSON())); const [singers] = await snapshot.read('Singers', { columns: ['SingerId', 'FirstName', 'LastName'], keySet: {all: true}, }); singers.forEach(row => console.log(row.toJSON())); } finally { snapshot.end(); await database.close(); } }); // With staleness bounds (for improved performance / availability) const [snapshot2] = await database.getSnapshot({exactStaleness: 15000}); // 15 seconds const [rows] = await snapshot2.run('SELECT 1'); snapshot2.end(); ``` -------------------------------- ### Add and Drop Database Role Source: https://github.com/googleapis/nodejs-spanner/blob/main/samples/README.md Demonstrates how to add and drop a new database role. Requires instance, database, and project IDs. ```javascript node add-and-drop-new-database-role.js ``` -------------------------------- ### Get Table Reference for Mutation-based CRUD Source: https://context7.com/googleapis/nodejs-spanner/llms.txt Obtain a table reference for performing mutation-based CRUD operations (insert, update, upsert, replace, deleteRows) that commit immediately without an explicit transaction. Ensure the database is closed in a `finally` block. ```javascript const {Spanner} = require('@google-cloud/spanner'); const spanner = new Spanner({projectId: 'my-project'}); const database = spanner.instance('my-instance').database('my-database'); const singersTable = database.table('Singers'); const albumsTable = database.table('Albums'); try { // Insert rows await singersTable.insert([ {SingerId: '1', FirstName: 'Marc', LastName: 'Richards'}, {SingerId: '2', FirstName: 'Catalina', LastName: 'Smith'}, ]); await albumsTable.insert([ {SingerId: '1', AlbumId: '1', AlbumTitle: 'Total Junk'}, {SingerId: '2', AlbumId: '1', AlbumTitle: 'Green'}, ]); // Update specific columns await albumsTable.update([ {SingerId: '1', AlbumId: '1', MarketingBudget: '100000'}, ]); // Upsert (insert or update) await singersTable.upsert([{SingerId: '3', FirstName: 'Alice', LastName: 'Trentor'}]); // Key-based read (point lookup) const [rows] = await albumsTable.read({ columns: ['SingerId', 'AlbumId', 'AlbumTitle'], keys: [['1', '1'], ['2', '1']], }); rows.forEach(row => console.log(row.toJSON())); // Delete specific rows by key await albumsTable.deleteRows([['2', '1']]); } catch (err) { console.error('ERROR:', err); } finally { await database.close(); } ``` -------------------------------- ### Run Unit Tests Source: https://github.com/googleapis/nodejs-spanner/blob/main/CONTRIBUTING.md Execute unit tests to verify the correctness of your code changes. ```bash # Run unit tests. npm test ``` -------------------------------- ### spanner.getInstances(options) / spanner.getInstancesStream() Source: https://context7.com/googleapis/nodejs-spanner/llms.txt Lists all instances in the project. Use the stream variant for large result sets. ```APIDOC ## spanner.getInstances(options) / spanner.getInstancesStream() — List instances Lists all instances in the project. Use the stream variant for large result sets. ```javascript const {Spanner} = require('@google-cloud/spanner'); const spanner = new Spanner({projectId: 'my-project'}); // Promise API — all pages auto-paginated const [instances] = await spanner.getInstances({ filter: 'labels.env:production', }); instances.forEach(inst => console.log(inst.formattedName_)); // Stream API — one instance object per 'data' event spanner .getInstancesStream() .on('error', console.error) .on('data', instance => console.log('Found:', instance.formattedName_)) .on('end', () => console.log('Done listing instances')); ``` ``` -------------------------------- ### spanner.getDatabaseAdminClient() / spanner.getInstanceAdminClient() Source: https://context7.com/googleapis/nodejs-spanner/llms.txt Returns shared, managed GAPIC client objects for direct access to the DatabaseAdmin and InstanceAdmin APIs. These clients should not be closed manually; closing the parent `Spanner` instance is sufficient. ```APIDOC ## `spanner.getDatabaseAdminClient()` / `spanner.getInstanceAdminClient()` ### Description Returns shared, managed GAPIC client objects for direct access to the DatabaseAdmin and InstanceAdmin APIs. Do not close these clients manually — closing the parent `Spanner` instance is sufficient. ### Usage ```javascript const {Spanner} = require('@google-cloud/spanner'); const spanner = new Spanner({projectId: 'my-project'}); const databaseAdminClient = spanner.getDatabaseAdminClient(); const instanceAdminClient = spanner.getInstanceAdminClient(); // Example: Create a database using the admin client directly const [operation] = await databaseAdminClient.createDatabase({ createStatement: 'CREATE DATABASE `my-database`', extraStatements: [ `CREATE TABLE Singers ( SingerId INT64 NOT NULL, FirstName STRING(1024), LastName STRING(1024) ) PRIMARY KEY (SingerId)`, `CREATE TABLE Albums ( SingerId INT64 NOT NULL, AlbumId INT64 NOT NULL, AlbumTitle STRING(MAX) ) PRIMARY KEY (SingerId, AlbumId), INTERLEAVE IN PARENT Singers ON DELETE CASCADE`, ], parent: databaseAdminClient.instancePath('my-project', 'my-instance'), }); await operation.promise(); console.log('Database created.'); spanner.close(); ``` ``` -------------------------------- ### new Spanner(options) Source: https://context7.com/googleapis/nodejs-spanner/llms.txt Creates the top-level Spanner client. It automatically accepts Application Default Credentials and supports the Spanner emulator. ```APIDOC ## new Spanner(options) — Create the top-level client The entry point for every interaction. Accepts Application Default Credentials automatically; pass `projectId` and optionally `keyFilename` for explicit credentials. Supports emulator via the `SPANNER_EMULATOR_HOST` environment variable. ```javascript const {Spanner} = require('@google-cloud/spanner'); // Using Application Default Credentials (ADC) const spanner = new Spanner({projectId: 'my-project'}); // Explicit service-account key file const spannerExplicit = new Spanner({ projectId: 'my-project', keyFilename: '/path/to/service-account.json', }); // Connecting to the Spanner emulator process.env.SPANNER_EMULATOR_HOST = 'localhost:9010'; const spannerEmulator = new Spanner({projectId: 'test-project'}); // With directed reads, leader-aware routing disabled, and built-in metrics off const spannerAdvanced = new Spanner({ projectId: 'my-project', routeToLeaderEnabled: false, disableBuiltInMetrics: true, directedReadOptions: { includeReplicas: { replicaSelections: [{location: 'us-east1', type: 'READ_ONLY'}], autoFailoverDisabled: true, }, }, }); // Always close the client when done to release gRPC resources spanner.close(); ``` ``` -------------------------------- ### Configure OpenTelemetry Tracing with `observabilityOptions` Source: https://context7.com/googleapis/nodejs-spanner/llms.txt Integrate the Spanner library with OpenTelemetry to emit distributed traces. Configure a tracer provider with Cloud Trace export and set observability options on the Spanner client for extended and end-to-end tracing. ```javascript const {NodeTracerProvider} = require('@opentelemetry/sdk-trace-node'); const {TraceExporter} = require('@google-cloud/opentelemetry-cloud-trace-exporter'); const {BatchSpanProcessor, TraceIdRatioBasedSampler} = require('@opentelemetry/sdk-trace-base'); const {propagation} = require('@opentelemetry/api'); const {W3CTraceContextPropagator} = require('@opentelemetry/core'); const {Spanner} = require('@google-cloud/spanner'); // Configure a tracer provider with Cloud Trace export const provider = new NodeTracerProvider({ sampler: new TraceIdRatioBasedSampler(1.0), // 100% sampling spanProcessors: [new BatchSpanProcessor(new TraceExporter({projectId: 'my-project'}))], }); propagation.setGlobalPropagator(new W3CTraceContextPropagator()); const spanner = new Spanner({ projectId: 'my-project', observabilityOptions: { tracerProvider: provider, enableExtendedTracing: true, // annotate spans with SQL text enableEndToEndTracing: true, // propagate trace context to the server }, disableBuiltInMetrics: false, // also export client-side metrics (default: enabled) }); const database = spanner.instance('my-instance').database('my-database'); const [rows] = await database.run({sql: 'SELECT 1'}); console.log(`Rows: ${rows.length}`); await provider.forceFlush(); // ensure all spans are exported before exit spanner.close(); ``` -------------------------------- ### Execute Partitioned DML on Spanner PostgreSQL Source: https://github.com/googleapis/nodejs-spanner/blob/main/README.md This sample demonstrates how to execute a Partitioned DML statement on a Spanner PostgreSQL database. Ensure you have the necessary permissions and a Spanner instance configured. ```javascript const {Spanner} = require('@google-cloud/spanner'); const spanner = new Spanner(); async function executePartitionedDml(instanceId, databaseId) { const instance = spanner.instance(instanceId); const database = instance.database(databaseId); // Partitioned DML statements are executed using the executePartitionedDml method. const sql = `UPDATE Singers SET SingerInfo = ST_INSERTBYKEY(SingerInfo, 'last_contacted', CURRENT_TIMESTAMP()) WHERE SingerId = 1`; try { const [rowCount] = await database.executePartitionedDml(sql); console.log(`Successfully executed partitioned DML. Rows affected: ${rowCount}`); } catch (err) { console.error('ERROR:', err); } finally { // Close the database connection. await database.close(); } } // TODO(developer): set your instance and database ID. // executePartitionedDml('my-instance', 'my-database'); ``` -------------------------------- ### Create Spanner Backup with Multiple KMS Keys Source: https://github.com/googleapis/nodejs-spanner/blob/main/samples/README.md Creates a Spanner backup using multiple KMS keys. ```javascript node samples/backups-create-with-multiple-kms-keys.js ``` -------------------------------- ### instance.database(name) Source: https://context7.com/googleapis/nodejs-spanner/llms.txt Returns a `Database` object, representing a specific database within an instance. The `database.get()` method can be used to create the database if `autoCreate` is set. ```APIDOC ## `instance.database(name)` ### Description Returns a `Database` object. The `database.get()` method creates the database if `autoCreate` is set. ### Usage ```javascript const {Spanner} = require('@google-cloud/spanner'); const spanner = new Spanner({projectId: 'my-project'}); const instance = spanner.instance('my-instance'); const database = instance.database('my-database'); // Check if the database exists const [exists] = await database.exists(); console.log('Exists:', exists); // Get or create the database const [db] = await database.get({autoCreate: true}); console.log('Database name:', db.formattedName_); await database.close(); // returns sessions to the pool ``` ``` -------------------------------- ### databaseAdminClient.createBackup(request) Source: https://context7.com/googleapis/nodejs-spanner/llms.txt Creates a point-in-time backup of a database as a long-running operation. ```APIDOC ## `databaseAdminClient.createBackup(request)` — Create a database backup Creates a point-in-time backup of a database as a long-running operation. ```javascript const {Spanner, protos} = require('@google-cloud/spanner'); const {PreciseDate} = require('@google-cloud/precise-date'); const spanner = new Spanner({projectId: 'my-project'}); const databaseAdminClient = spanner.getDatabaseAdminClient(); const expireTime = Date.now() + 1000 * 60 * 60 * 24 * 14; // 14 days const versionTime = Date.now() - 1000 * 60 * 60; // 1 hour ago try { const [operation] = await databaseAdminClient.createBackup({ parent: databaseAdminClient.instancePath('my-project', 'my-instance'), backupId: 'my-backup', backup: (protos.google.spanner.admin.database.v1.Backup = { database: databaseAdminClient.databasePath('my-project', 'my-instance', 'my-database'), expireTime: Spanner.timestamp(expireTime).toStruct(), versionTime: Spanner.timestamp(versionTime).toStruct(), name: databaseAdminClient.backupPath('my-project', 'my-instance', 'my-backup'), }), }); await operation.promise(); const [backupInfo] = await databaseAdminClient.getBackup({ name: databaseAdminClient.backupPath('my-project', 'my-instance', 'my-backup'), }); console.log( `Backup ${backupInfo.name} (${backupInfo.sizeBytes} bytes) ` + `created at ${new PreciseDate(backupInfo.createTime).toISOString()}`, ); } finally { spanner.close(); } ``` ``` -------------------------------- ### Configure OpenTelemetry Tracer Provider Source: https://github.com/googleapis/nodejs-spanner/blob/main/OBSERVABILITY.md Set up the NodeTracerProvider with a Cloud Trace exporter and BatchSpanProcessor. This configuration is then passed to the Spanner client's observability options. ```javascript const { NodeTracerProvider, TraceIdRatioBasedSampler, } = require('@opentelemetry/sdk-trace-node'); const { BatchSpanProcessor, } = require('@opentelemetry/sdk-trace-base'); const { TraceExporter, } = require('@google-cloud/opentelemetry-cloud-trace-exporter'); const exporter = new TraceExporter(); // Create the tracerProvider that the exporter shall be attached to. const provider = new NodeTracerProvider({ resource: resource, spanProcessors: [new BatchSpanProcessor(exporter)] }); // Create the Cloud Spanner Client. const {Spanner} = require('@google-cloud/spanner'); const spanner = new Spanner({ projectId: projectId, observabilityOptions: { // Inject the TracerProvider via SpannerOptions or // register it as a global by invoking `provider.register()` tracerProvider: provider, }, }); ``` -------------------------------- ### Create Spanner Backup Source: https://github.com/googleapis/nodejs-spanner/blob/main/samples/README.md Creates a Spanner backup. ```javascript node samples/backups-create.js ``` -------------------------------- ### Set Environment Variables for Benchmarking Source: https://github.com/googleapis/nodejs-spanner/blob/main/benchmark/README.md Environment variables to configure Google Cloud credentials and project for YCSB benchmarking. ```sh $ export GOOGLE_APPLICATION_CREDENTIALS=/usr/local/google/home/haih/cloud-spanner-client-benchmark.json $ export GCLOUD_PROJECT=cloud-spanner-client-benchmark ``` -------------------------------- ### Create Cloud Spanner Instance and Database Source: https://github.com/googleapis/nodejs-spanner/blob/main/benchmark/README.md Commands to create a Cloud Spanner instance and database, followed by updating the database schema with a 'usertable'. ```sh $ gcloud spanner instances create ycsb-instance --nodes 1 \ --config regional-us-central1 --description YCSB $ gcloud spanner databases create ycsb --instance ycsb-instance $ gcloud spanner databases ddl update ycsb --instance ycsb-instance \ --ddl="CREATE TABLE usertable ( id STRING(MAX), field0 STRING(MAX), field1 STRING(MAX), field2 STRING(MAX), field3 STRING(MAX), field4 STRING(MAX), field5 STRING(MAX), field6 STRING(MAX), field7 STRING(MAX), field8 STRING(MAX), field9 STRING(MAX), ) PRIMARY KEY(id)" ``` -------------------------------- ### Copy Spanner Backup with Multiple KMS Keys Source: https://github.com/googleapis/nodejs-spanner/blob/main/samples/README.md Copies a Spanner backup using multiple KMS keys. Requires instance, copy backup, source backup, and project IDs. ```javascript node spannerCopyBackup ``` -------------------------------- ### Create a Point-in-Time Database Backup Source: https://context7.com/googleapis/nodejs-spanner/llms.txt Creates a backup of a Spanner database at a specific point in time. This is a long-running operation. It sets an expiration time and version time for the backup and retrieves backup information upon completion. ```javascript const {Spanner, protos} = require('@google-cloud/spanner'); const {PreciseDate} = require('@google-cloud/precise-date'); const spanner = new Spanner({projectId: 'my-project'}); const databaseAdminClient = spanner.getDatabaseAdminClient(); const expireTime = Date.now() + 1000 * 60 * 60 * 24 * 14; // 14 days const versionTime = Date.now() - 1000 * 60 * 60; // 1 hour ago try { const [operation] = await databaseAdminClient.createBackup({ parent: databaseAdminClient.instancePath('my-project', 'my-instance'), backupId: 'my-backup', backup: (protos.google.spanner.admin.database.v1.Backup = { database: databaseAdminClient.databasePath('my-project', 'my-instance', 'my-database'), expireTime: Spanner.timestamp(expireTime).toStruct(), versionTime: Spanner.timestamp(versionTime).toStruct(), name: databaseAdminClient.backupPath('my-project', 'my-instance', 'my-backup'), }), }); await operation.promise(); const [backupInfo] = await databaseAdminClient.getBackup({ name: databaseAdminClient.backupPath('my-project', 'my-instance', 'my-backup'), }); console.log( `Backup ${backupInfo.name} (${backupInfo.sizeBytes} bytes) ` + `created at ${new PreciseDate(backupInfo.createTime).toISOString()}`, ); } finally { spanner.close(); } ``` -------------------------------- ### `database.runTransaction(callback)` / `database.runTransactionAsync(callback)` Source: https://context7.com/googleapis/nodejs-spanner/llms.txt Runs a read-write transaction with automatic retry on `ABORTED`. Use `runTransactionAsync` when you need to `await` the result. ```APIDOC ## `database.runTransaction(callback)` / `database.runTransactionAsync(callback)` — Read-write transactions Runs a read-write transaction with automatic retry on `ABORTED`. Use `runTransactionAsync` when you need to `await` the result. ```javascript const {Spanner} = require('@google-cloud/spanner'); const spanner = new Spanner({projectId: 'my-project'}); const database = spanner.instance('my-instance').database('my-database'); // Async variant — returns a Promise await database.runTransactionAsync(async transaction => { try { // Read inside transaction const [rows] = await transaction.read('Albums', { columns: ['MarketingBudget'], keys: [[1, 1]], }); const currentBudget = rows[0].toJSON().MarketingBudget; console.log('Current budget:', currentBudget); // DML update inside transaction const [rowCount] = await transaction.runUpdate({ sql: 'UPDATE Albums SET MarketingBudget = @budget WHERE SingerId = 1 AND AlbumId = 1', params: {budget: Spanner.int(currentBudget + 50000)}, }); console.log(`Updated ${rowCount} row(s).`); // Mutation-style update inside transaction transaction.update('Albums', [{SingerId: '2', AlbumId: '2', MarketingBudget: '500000'}]); // Commit all changes atomically const [commitResponse] = await transaction.commit({returnCommitStats: true}); console.log('Committed at:', commitResponse.commitTimestamp); console.log('Mutation count:', commitResponse.commitStats?.mutationCount); } catch (err) { console.error('Transaction failed:', err); throw err; // rethrow to trigger rollback / retry } }); await database.close(); ``` ``` -------------------------------- ### spanner.createInstance(name, config) Source: https://context7.com/googleapis/nodejs-spanner/llms.txt Creates a new Spanner instance as a long-running operation. Returns a promise that resolves to `[Instance, Operation, apiResponse]`. ```APIDOC ## spanner.createInstance(name, config) — Create a Spanner instance Creates a new Spanner instance as a long-running operation. Returns a promise that resolves to `[Instance, Operation, apiResponse]`. ```javascript const {Spanner} = require('@google-cloud/spanner'); const spanner = new Spanner({projectId: 'my-project'}); async function main() { try { const [instance, operation] = await spanner.createInstance('my-instance', { config: 'regional-us-central1', // or 'nam6' for multi-region nodes: 1, displayName: 'My Spanner Instance', labels: {env: 'production', team: 'backend'}, }); console.log(`Waiting for instance creation to complete...`); await operation.promise(); console.log(`Instance ${instance.formattedName_} created.`); } catch (err) { console.error('Failed to create instance:', err); } finally { spanner.close(); } } main(); ``` ``` -------------------------------- ### Create Spanner Backup with Encryption Key Source: https://github.com/googleapis/nodejs-spanner/blob/main/samples/README.md Creates a Spanner backup using a specific encryption key. ```javascript node samples/backups-create-with-encryption-key.js ``` -------------------------------- ### database.run(query) Source: https://context7.com/googleapis/nodejs-spanner/llms.txt Executes a SQL query against the database and returns all rows as an array. For large result sets, `database.runStream()` is recommended. ```APIDOC ## `database.run(query)` ### Description Executes a SQL query and returns all rows as an array. Use `database.runStream()` for large result sets. ### Usage ```javascript const {Spanner} = require('@google-cloud/spanner'); const spanner = new Spanner({projectId: 'my-project'}); const database = spanner.instance('my-instance').database('my-database'); try { // Simple query const [rows] = await database.run({ sql: 'SELECT SingerId, AlbumId, AlbumTitle FROM Albums', }); rows.forEach(row => { const json = row.toJSON(); console.log(`${json.SingerId} | ${json.AlbumId} | ${json.AlbumTitle}`); }); // Parameterized query (preferred to avoid SQL injection) const [filtered] = await database.run({ sql: 'SELECT * FROM Singers WHERE FirstName = @name', params: {name: 'Alice'}, // Optionally return as plain JSON objects directly json: true, }); filtered.forEach(row => console.log(row)); // plain JS objects // Stream large results database .runStream({sql: 'SELECT SingerId FROM Singers'}) .on('error', console.error) .on('data', row => console.log(row.toJSON())) .on('end', () => console.log('Stream finished')); } finally { await database.close(); } ``` ``` -------------------------------- ### Enable End-to-End Tracing Source: https://github.com/googleapis/nodejs-spanner/blob/main/OBSERVABILITY.md Configure end-to-end tracing by setting the SPANNER_ENABLE_END_TO_END_TRACING environment variable or `enableEndToEndTracing: true` in SpannerOptions, and set trace context propagation. ```javascript const spanner = new Spanner({ projectId: projectId, observabilityOptions: { tracerProvider: provider, enableEndToEndTracing: true, } }), ``` ```javascript const { propagation } = require('@opentelemetry/api'); const { W3CTraceContextPropagator } = require('@opentelemetry/core'); propagation.setGlobalPropagator(new W3CTraceContextPropagator()); ``` -------------------------------- ### Execute DML with Parameters on Spanner PostgreSQL Source: https://github.com/googleapis/nodejs-spanner/blob/main/README.md This sample demonstrates executing a DML statement with parameters on a Spanner PostgreSQL database. Using parameters helps prevent SQL injection and improves query performance. ```javascript const {Spanner} = require('@google-cloud/spanner'); const spanner = new Spanner(); async function executeDmlWithParameters(instanceId, databaseId) { const instance = spanner.instance(instanceId); const database = instance.database(databaseId); // DML statements with parameters are executed using the run method. // Parameters are passed as an array of objects. const sql = { text: `UPDATE Singers SET SingerName = @singerName WHERE SingerId = @singerId`, params: { singerName: 'New Singer Name', singerId: 1, }, }; try { const [rowCount] = await database.run(sql); console.log(`Successfully updated ${rowCount} records.`); } catch (err) { console.error('ERROR:', err); } finally { // Close the database connection. await database.close(); } } // TODO(developer): set your instance and database ID. // executeDmlWithParameters('my-instance', 'my-database'); ``` -------------------------------- ### Insert using DML Returning on Spanner PostgreSQL Source: https://github.com/googleapis/nodejs-spanner/blob/main/README.md This sample demonstrates how to insert data into a Spanner PostgreSQL table using DML and retrieve the inserted data with a RETURNING clause. This is useful for confirming inserted values. ```javascript const {Spanner} = require('@google-cloud/spanner'); const spanner = new Spanner(); async function insertWithDmlReturning(instanceId, databaseId) { const instance = spanner.instance(instanceId); const database = instance.database(databaseId); // DML statements with a RETURNING clause are executed using the run method. const sql = `INSERT INTO Singers (SingerId, SingerName) VALUES (2, 'Alice') RETURNING SingerId, SingerName`; try { const [rowCount, , records] = await database.run(sql); console.log(`Successfully inserted ${rowCount} records.`); console.log('Inserted records:', JSON.stringify(records, null, 2)); } catch (err) { console.error('ERROR:', err); } finally { // Close the database connection. await database.close(); } } // TODO(developer): set your instance and database ID. // insertWithDmlReturning('my-instance', 'my-database'); ``` -------------------------------- ### spanner.instance(name) Source: https://context7.com/googleapis/nodejs-spanner/llms.txt Returns an `Instance` object without making an API call. Use the returned handle to manage databases and query instance metadata. ```APIDOC ## spanner.instance(name) — Get an Instance reference Returns an `Instance` object without making an API call. Use the returned handle to manage databases and query instance metadata. ```javascript const {Spanner} = require('@google-cloud/spanner'); const spanner = new Spanner({projectId: 'my-project'}); const instance = spanner.instance('my-instance'); // Get instance metadata const [metadata] = await instance.get(); console.log('Instance config:', metadata.config); console.log('Node count:', metadata.nodeCount); // List databases on the instance const [databases] = await instance.getDatabases(); databases.forEach(db => console.log('Database:', db.formattedName_)); // Delete the instance await instance.delete(); ``` ``` -------------------------------- ### Create Storing Index on Spanner PostgreSQL Source: https://github.com/googleapis/nodejs-spanner/blob/main/README.md This sample demonstrates how to create a new storing index in a Spanner PostgreSQL database. Storing indexes can improve query performance by including additional columns. ```javascript const {Spanner} = require('@google-cloud/spanner'); const spanner = new Spanner(); async function createStoringIndex(instanceId, databaseId) { const instance = spanner.instance(instanceId); const database = instance.database(databaseId); // DDL statements are executed using the updateDatabase method. const ddl = [ `CREATE INDEX MyStoringIndex ON Singers(SingerName) STORING (SingerId, Album)`, ]; try { const [operation] = await database.updateDatabase(ddl); console.log('Waiting for operation to complete...'); await operation.promise(); console.log('Created storing index `MyStoringIndex` successfully.'); } catch (err) { console.error('ERROR:', err); } finally { // Close the database connection. await database.close(); } } // TODO(developer): set your instance and database ID. // createStoringIndex('my-instance', 'my-database'); ``` -------------------------------- ### Run YCSB Benchmarks with Custom Parameters Source: https://github.com/googleapis/nodejs-spanner/blob/main/benchmark/README.md Executes YCSB benchmarks directly using Node.js, allowing for custom parameter configuration. ```sh node benchmarks/ycsb.js run -P benchmarks/workloada -p table=usertable \ -p cloudspanner.instance=ycsb-542756a4 -p recordcount=5000 \ -p operationcount=100 -p cloudspanner.database=ycsb -p num_worker=1 ``` -------------------------------- ### List Spanner Instances Source: https://context7.com/googleapis/nodejs-spanner/llms.txt List all Spanner instances within a project using either a Promise-based API with auto-pagination or a Stream API for large result sets. Filtering by labels is supported. ```javascript const {Spanner} = require('@google-cloud/spanner'); const spanner = new Spanner({projectId: 'my-project'}); // Promise API — all pages auto-paginated const [instances] = await spanner.getInstances({ filter: 'labels.env:production', }); instances.forEach(inst => console.log(inst.formattedName_)); // Stream API — one instance object per 'data' event spanner .getInstancesStream() .on('error', console.error) .on('data', instance => console.log('Found:', instance.formattedName_)) .on('end', () => console.log('Done listing instances')); ``` -------------------------------- ### Create Spanner Instance Source: https://context7.com/googleapis/nodejs-spanner/llms.txt Create a new Spanner instance using the client library. This is a long-running operation. Ensure the client is closed in a finally block. ```javascript const {Spanner} = require('@google-cloud/spanner'); const spanner = new Spanner({projectId: 'my-project'}); async function main() { try { const [instance, operation] = await spanner.createInstance('my-instance', { config: 'regional-us-central1', // or 'nam6' for multi-region nodes: 1, displayName: 'My Spanner Instance', labels: {env: 'production', team: 'backend'}, }); console.log(`Waiting for instance creation to complete...`); await operation.promise(); console.log(`Instance ${instance.formattedName_} created.`); } catch (err) { console.error('Failed to create instance:', err); } finally { spanner.close(); } } main(); ``` -------------------------------- ### `database.getSnapshot(options)` Source: https://context7.com/googleapis/nodejs-spanner/llms.txt Returns a `Snapshot` object representing a consistent read at a point in time. No locking, highly scalable for read-heavy workloads. ```APIDOC ## `database.getSnapshot(options)` — Read-only (snapshot) transactions Returns a `Snapshot` object representing a consistent read at a point in time. No locking, highly scalable for read-heavy workloads. ```javascript const {Spanner} = require('@google-cloud/spanner'); const spanner = new Spanner({projectId: 'my-project'}); const database = spanner.instance('my-instance').database('my-database'); database.getSnapshot(async (err, snapshot) => { if (err) { console.error(err); return; } try { // Both reads below see the exact same database state const [albums] = await snapshot.run('SELECT AlbumId, AlbumTitle FROM Albums'); albums.forEach(row => console.log(row.toJSON())); const [singers] = await snapshot.read('Singers', { columns: ['SingerId', 'FirstName', 'LastName'], keySet: {all: true}, }); singers.forEach(row => console.log(row.toJSON())); } finally { snapshot.end(); await database.close(); } }); // With staleness bounds (for improved performance / availability) const [snapshot2] = await database.getSnapshot({exactStaleness: 15000}); // 15 seconds const [rows] = await snapshot2.run('SELECT 1'); snapshot2.end(); ``` ``` -------------------------------- ### database.table(name) Source: https://context7.com/googleapis/nodejs-spanner/llms.txt Provides mutation APIs (`insert`, `update`, `upsert`, `replace`, `deleteRows`) for a specific table. Each mutation call commits immediately. ```APIDOC ## `database.table(name)` ### Description Provides mutation APIs (`insert`, `update`, `upsert`, `replace`, `deleteRows`) that do not require an explicit transaction object. Each call commits immediately. ### Usage ```javascript const {Spanner} = require('@google-cloud/spanner'); const spanner = new Spanner({projectId: 'my-project'}); const database = spanner.instance('my-instance').database('my-database'); const singersTable = database.table('Singers'); const albumsTable = database.table('Albums'); try { // Insert rows await singersTable.insert([ {SingerId: '1', FirstName: 'Marc', LastName: 'Richards'}, {SingerId: '2', FirstName: 'Catalina', LastName: 'Smith'}, ]); await albumsTable.insert([ {SingerId: '1', AlbumId: '1', AlbumTitle: 'Total Junk'}, {SingerId: '2', AlbumId: '1', AlbumTitle: 'Green'}, ]); // Update specific columns await albumsTable.update([ {SingerId: '1', AlbumId: '1', MarketingBudget: '100000'}, ]); // Upsert (insert or update) await singersTable.upsert([{SingerId: '3', FirstName: 'Alice', LastName: 'Trentor'}]); // Key-based read (point lookup) const [rows] = await albumsTable.read({ columns: ['SingerId', 'AlbumId', 'AlbumTitle'], keys: [['1', '1'], ['2', '1']], }); rows.forEach(row => console.log(row.toJSON())); // Delete specific rows by key await albumsTable.deleteRows([['2', '1']]); } catch (err) { console.error('ERROR:', err); } finally { await database.close(); } ``` ``` -------------------------------- ### Load Data using YCSB Source: https://github.com/googleapis/nodejs-spanner/blob/main/benchmark/README.md Commands to download the YCSB Cloud Spanner binding and load data into the Spanner database. ```sh $ curl https://storage.googleapis.com/cloud-spanner-ycsb-custom-release/ycsb-cloudspanner-binding-0.13.0.tar.gz | tar -xzv $ ycsb-cloudspanner-binding-0.13.0/bin/ycsb load cloudspanner \ -P ycsb-cloudspanner-binding-0.13.0/workloads/workloada \ -p table=usertable -p cloudspanner.instance=ycsb-instance \ -p recordcount=5000 -p operationcount=100 -p cloudspanner.database=ycsb \ -threads 32 ```