Amazon QLDB driver for Node.js – Quick start tutorial - Amazon Quantum Ledger Database (Amazon QLDB)

Amazon QLDB driver for Node.js – Quick start tutorial

In this tutorial, you learn how to set up a simple application using the Amazon QLDB driver for Node.js. This guide includes steps for installing the driver, and short JavaScript and TypeScript code examples of basic create, read, update, and delete (CRUD) operations. For more in-depth examples that demonstrate these operations in a full sample application, see the Node.js tutorial.

Note

Where applicable, some steps have different code examples for each supported major version of the QLDB driver for Node.js.

Prerequisites

Before you get started, make sure that you do the following:

  1. Complete the Prerequisites for the Node.js driver, if you haven't already done so. This includes signing up for AWS, getting an AWS access key for development, and installing Node.js.

  2. Create a ledger named quick-start.

    To learn how to create a ledger, see Basic operations for Amazon QLDB ledgers or Step 1: Create a new ledger in Getting started with the console.

If you're using TypeScript, you must also do the following setup steps.

To install TypeScript

  1. Install the TypeScript package. The QLDB driver runs on TypeScript 3.5.x.

    $ npm install --global typescript@3.5.1
  2. After the package is installed, run the following command to make sure that the TypeScript compiler is installed.

    $ tsc --version

To run the code in the following steps, note that you must first transpile your TypeScript file to executable JavaScript code, as follows.

$ tsc app.ts; node app.js

Step 1: Set up your project

First, set up your Node.js project.

  1. Create a folder for your application.

    $ mkdir myproject $ cd myproject
  2. To initialize your project, enter the following npm command and answer the questions that are asked during the setup. You can use defaults for most of the questions.

    $ npm init
  3. Install the Amazon QLDB driver for Node.js.

    • Using version 2.x

      $ npm install amazon-qldb-driver-nodejs --save
    • Using version 1.x

      $ npm install amazon-qldb-driver-nodejs@1.0.0 --save
  4. Install the peer dependencies of the driver.

    $ npm install aws-sdk --save $ npm install ion-js@4.0.0 --save $ npm install jsbi@3.1.2 --save
  5. Create a new file named app.js for JavaScript, or app.ts for TypeScript.

    Then, incrementally add the code examples in the following steps to try some basic CRUD operations. Or, you can skip the step-by-step tutorial and instead run the complete application.

Step 2: Initialize the driver

Initialize an instance of the driver that connects to the ledger named quick-start. Add the following code to your app.js or app.ts file.

Using version 2.x

JavaScript
var qldb = require('amazon-qldb-driver-nodejs'); var https = require('https'); function main() { var maxConcurrentTransactions = 10; var retryLimit = 4; var agentForQldb = new https.Agent({ keepAlive: true, maxSockets: maxConcurrentTransactions }); var serviceConfigurationOptions = { region: "us-east-1", httpOptions: { agent: agentForQldb } }; // Use driver's default backoff function for this example (no second parameter provided to RetryConfig) var retryConfig = new qldb.RetryConfig(retryLimit); var driver = new qldb.QldbDriver("quick-start", serviceConfigurationOptions, maxConcurrentTransactions, retryConfig); } main();
TypeScript
import { QldbDriver, RetryConfig } from "amazon-qldb-driver-nodejs"; import { ClientConfiguration } from "aws-sdk/clients/acm"; import { Agent } from "https"; function main(): void { const maxConcurrentTransactions: number = 10; const agentForQldb: Agent = new Agent({ keepAlive: true, maxSockets: maxConcurrentTransactions }); const serviceConfigurationOptions: ClientConfiguration = { region: "us-east-1", httpOptions: { agent: agentForQldb } }; const retryLimit: number = 4; // Use driver's default backoff function for this example (no second parameter provided to RetryConfig) const retryConfig: RetryConfig = new RetryConfig(retryLimit); const driver: QldbDriver = new QldbDriver("quick-start", serviceConfigurationOptions, maxConcurrentTransactions, retryConfig); } if (require.main === module) { main(); }
Note
  • In this code example, replace us-east-1 with the AWS Region where you created your ledger.

  • Version 2.x introduces the new optional parameter RetryConfig for initializing QldbDriver.

  • For simplicity, the remaining code examples in this guide use a driver with default settings, as specified in the following example for version 1.x. You can also use your own driver instance with a custom RetryConfig instead.

  • This code example initializes a driver that reuses existing connections by setting Keep-Alive options. To learn more, see Setup recommendations for the Node.js driver.

Using version 1.x

JavaScript
const qldb = require('amazon-qldb-driver-nodejs'); function main() { // Use default settings const driver = new qldb.QldbDriver("quick-start"); } main();
TypeScript
import { QldbDriver } from "amazon-qldb-driver-nodejs"; function main(): void { // Use default settings const driver: QldbDriver = new QldbDriver("quick-start"); } if (require.main === module) { main(); }
Note

You can set the AWS_REGION environment variable to specify the Region. For more information, see Setting the AWS Region in the AWS SDK for JavaScript Developer Guide.

Step 3: Create a table and an index

The following code examples show how to run CREATE TABLE and CREATE INDEX statements.

  1. Add the following function that creates a table named People.

    JavaScript
    async function createTable(txn) { await txn.execute("CREATE TABLE People"); }
    TypeScript
    async function createTable(txn: TransactionExecutor): Promise<void> { await txn.execute("CREATE TABLE People"); }
  2. Add the following function that creates an index for the firstName field on the People table. Indexes are required to optimize query performance and help to limit optimistic concurrency control (OCC) conflict exceptions.

    JavaScript
    async function createIndex(txn) { await txn.execute("CREATE INDEX ON People (firstName)"); }
    TypeScript
    async function createIndex(txn: TransactionExecutor): Promise<void> { await txn.execute("CREATE INDEX ON People (firstName)"); }
  3. In the main function, you first call createTable, and then call createIndex.

    JavaScript
    const qldb = require('amazon-qldb-driver-nodejs'); async function main() { // Use default settings const driver = new qldb.QldbDriver("quick-start"); await driver.executeLambda(async (txn) => { console.log("Create table People"); await createTable(txn); console.log("Create index on firstName"); await createIndex(txn); }); driver.close(); } main();
    TypeScript
    import { QldbDriver, TransactionExecutor } from "amazon-qldb-driver-nodejs"; async function main(): Promise<void> { // Use default settings const driver: QldbDriver = new QldbDriver("quick-start"); await driver.executeLambda(async (txn: TransactionExecutor) => { console.log("Create table People"); await createTable(txn); console.log("Create index on firstName"); await createIndex(txn); }); driver.close(); } if (require.main === module) { main(); }
  4. Run the code to create the table and index.

    JavaScript
    $ node app.js
    TypeScript
    $ tsc app.ts; node app.js

Step 4: Insert a document

The following code example shows how to run an INSERT statement. QLDB supports the PartiQL query language (SQL compatible) and the Amazon Ion data format (superset of JSON).

  1. Add the following function that inserts a document into the People table.

    JavaScript
    async function insertDocument(txn) { const person = { firstName: "John", lastName: "Doe", age: 42 }; await txn.execute("INSERT INTO People ?", person); }
    TypeScript
    async function insertDocument(txn: TransactionExecutor): Promise<void> { const person: Record<string, any> = { firstName: "John", lastName: "Doe", age: 42 }; await txn.execute("INSERT INTO People ?", person); }

    This example uses a question mark (?) as a variable placeholder to pass the document information to the statement. The execute method supports values in both Amazon Ion types and Node.js native types.

    Tip

    To insert multiple documents by using a single INSERT statement, you can pass a parameter of type list to the statement as follows.

    // people is a list txn.execute("INSERT INTO People ?", people);

    You don't enclose the variable placeholder (?) in double angle brackets ( <<...>> ) when passing a list. In manual PartiQL statements, double angle brackets denote an unordered collection known as a bag.

  2. In the main function, remove the createTable and createIndex calls, and add a call to insertDocument.

    JavaScript
    const qldb = require('amazon-qldb-driver-nodejs'); async function main() { // Use default settings const driver = new qldb.QldbDriver("quick-start"); await driver.executeLambda(async (txn) => { console.log("Insert document"); await insertDocument(txn); }); driver.close(); } main();
    TypeScript
    import { QldbDriver, TransactionExecutor } from "amazon-qldb-driver-nodejs"; async function main(): Promise<void> { // Use default settings const driver: QldbDriver = new QldbDriver("quick-start"); await driver.executeLambda(async (txn: TransactionExecutor) => { console.log("Insert document"); await insertDocument(txn); }); driver.close(); } if (require.main === module) { main(); }

Step 5: Query the document

The following code example shows how to run a SELECT statement.

  1. Add the following function that queries a document from the People table.

    JavaScript
    async function fetchDocuments(txn) { return await txn.execute("SELECT firstName, age, lastName FROM People WHERE firstName = ?", "John"); }
    TypeScript
    async function fetchDocuments(txn: TransactionExecutor): Promise<dom.Value[]> { return (await txn.execute("SELECT firstName, age, lastName FROM People WHERE firstName = ?", "John")).getResultList(); }
  2. In the main function, add the following call to fetchDocuments after the call to insertDocument.

    JavaScript
    const qldb = require('amazon-qldb-driver-nodejs'); async function main() { // Use default settings const driver = new qldb.QldbDriver("quick-start"); var resultList = await driver.executeLambda(async (txn) => { console.log("Insert document"); await insertDocument(txn); console.log("Fetch document"); var result = await fetchDocuments(txn); return result.getResultList(); }); // Pretty print the result list console.log("The result List is ", JSON.stringify(resultList, null, 2)); driver.close(); } main();
    TypeScript
    import { QldbDriver, TransactionExecutor } from "amazon-qldb-driver-nodejs"; import { dom } from "ion-js"; async function main(): Promise<void> { // Use default settings const driver: QldbDriver = new QldbDriver("quick-start"); const resultList: dom.Value[] = await driver.executeLambda(async (txn: TransactionExecutor) => { console.log("Insert document"); await insertDocument(txn); console.log("Fetch document"); return await fetchDocuments(txn); }); // Pretty print the result list console.log("The result List is ", JSON.stringify(resultList, null, 2)); driver.close(); } if (require.main === module) { main(); }

Step 6: Update the document

The following code example shows how to run an UPDATE statement.

  1. Add the following function that updates a document in the People table by changing lastName to "Stiles".

    JavaScript
    async function updateDocuments(txn) { await txn.execute("UPDATE People SET lastName = ? WHERE firstName = ?", "Stiles", "John"); }
    TypeScript
    async function updateDocuments(txn: TransactionExecutor): Promise<void> { await txn.execute("UPDATE People SET lastName = ? WHERE firstName = ?", "Stiles", "John"); }
  2. In the main function, add the following call to updateDocuments after the call to fetchDocuments. Then, call fetchDocuments again to see the updated results.

    JavaScript
    const qldb = require('amazon-qldb-driver-nodejs'); async function main() { // Use default settings const driver = new qldb.QldbDriver("quick-start"); var resultList = await driver.executeLambda(async (txn) => { console.log("Insert document"); await insertDocument(txn); console.log("Fetch document"); await fetchDocuments(txn); console.log("Update document"); await updateDocuments(txn); console.log("Fetch document after update"); var result = await fetchDocuments(txn); return result.getResultList(); }); // Pretty print the result list console.log("The result List is ", JSON.stringify(resultList, null, 2)); driver.close(); } main();
    TypeScript
    import { QldbDriver, TransactionExecutor } from "amazon-qldb-driver-nodejs"; import { dom } from "ion-js"; async function main(): Promise<void> { // Use default settings const driver: QldbDriver = new QldbDriver("quick-start"); const resultList: dom.Value[] = await driver.executeLambda(async (txn: TransactionExecutor) => { console.log("Insert document"); await insertDocument(txn); console.log("Fetch document"); await fetchDocuments(txn); console.log("Update document"); await updateDocuments(txn); console.log("Fetch document after update"); await fetchDocuments(txn); }); // Pretty print the result list console.log("The result List is ", JSON.stringify(resultList, null, 2)); driver.close(); } if (require.main === module) { main(); }
  3. Run the code to insert, query, and update a document.

    JavaScript
    $ node app.js
    TypeScript
    $ tsc app.ts; node app.js

Running the complete application

The following code examples are the complete versions of app.js and app.ts. Instead of doing the previous steps individually, you can also run this code end to end. This application demonstrates some basic CRUD operations on the ledger named quick-start.

Note

Before you run this code, make sure that you don't already have an active table named People in the quick-start ledger.

JavaScript
const qldb = require('amazon-qldb-driver-nodejs'); async function createTable(txn) { await txn.execute("CREATE TABLE People"); } async function createIndex(txn) { await txn.execute("CREATE INDEX ON People (firstName)"); } async function insertDocument(txn) { const person = { firstName: "John", lastName: "Doe", age: 42 }; await txn.execute("INSERT INTO People ?", person); } async function fetchDocuments(txn) { return await txn.execute("SELECT firstName, age, lastName FROM People WHERE firstName = ?", "John"); } async function updateDocuments(txn) { await txn.execute("UPDATE People SET lastName = ? WHERE firstName = ?", "Stiles", "John"); } async function main() { // Use default settings const driver = new qldb.QldbDriver("quick-start"); var resultList = await driver.executeLambda(async (txn) => { console.log("Create table People"); await createTable(txn); console.log("Create index on firstName"); await createIndex(txn); console.log("Insert document"); await insertDocument(txn); console.log("Fetch document"); await fetchDocuments(txn); console.log("Update document"); await updateDocuments(txn); console.log("Fetch document after update"); var result = await fetchDocuments(txn); return result.getResultList(); }); // Pretty print the result list console.log("The result List is ", JSON.stringify(resultList, null, 2)); driver.close(); } main();
TypeScript
import { QldbDriver, TransactionExecutor } from "amazon-qldb-driver-nodejs"; import { dom } from "ion-js"; async function createTable(txn: TransactionExecutor): Promise<void> { await txn.execute("CREATE TABLE People"); } async function createIndex(txn: TransactionExecutor): Promise<void> { await txn.execute("CREATE INDEX ON People (firstName)"); } async function insertDocument(txn: TransactionExecutor): Promise<void> { const person: Record<string, any> = { firstName: "John", lastName: "Doe", age: 42 }; await txn.execute("INSERT INTO People ?", person); } async function fetchDocuments(txn: TransactionExecutor): Promise<dom.Value[]> { return (await txn.execute("SELECT firstName, age, lastName FROM People WHERE firstName = ?", "John")).getResultList(); } async function updateDocuments(txn: TransactionExecutor): Promise<void> { await txn.execute("UPDATE People SET lastName = ? WHERE firstName = ?", "Stiles", "John"); }; async function main(): Promise<void> { // Use default settings const driver: QldbDriver = new QldbDriver("quick-start"); const resultList: dom.Value[] = await driver.executeLambda(async (txn: TransactionExecutor) => { console.log("Create table People"); await createTable(txn); console.log("Create index on firstName"); await createIndex(txn); console.log("Insert document"); await insertDocument(txn); console.log("Fetch document"); await fetchDocuments(txn); console.log("Update document"); await updateDocuments(txn); console.log("Fetch document after update"); return await fetchDocuments(txn); }); // Pretty print the result list console.log("The result List is ", JSON.stringify(resultList, null, 2)); driver.close(); } if (require.main === module) { main(); }

To run the complete application, enter the following command.

JavaScript
$ node app.js
TypeScript
$ tsc app.ts; node app.js