Initialize AWS DynamoDB on local

How to initialize AWS DynamoDB on local with Nodejs

Install aws cli on your local. Follow the steps here.

Check if your installation is successful by running:

aws --version

aws-cli/2.4.8 Python/3.8.8 Linux/5.11.0-44-generic exe/x86_64.ubuntu.20 prompt/off

If the above command works, run the following with dummy values.

aws configure

AWS Access Key ID [None]: hello
AWS Secret Access Key [None]: world
Default region name [None]: local
Default output format [None]: json

Creating library for getting Database instance

const AWS = require('aws-sdk')
// TODO. pass params from CLI
AWS.config.update({
  region: 'local',
  endpoint: 'http://localhost:8000'
})

let dbInstance
let dbClient

export function getDbInstance() {
  if (dbInstance) return dbInstance
  else {
    dbInstance = new AWS.DynamoDB({ apiVersion: '2012-08-10' })
    return dbInstance
  }
}

export function getDbClient() {
  if (dbClient) return dbClient
  else {
    dbClient = new AWS.DynamoDB.DocumentClient({ apiVersion: '2012-08-10' })
    return dbClient
  }
}

So, Here we are using aws-sdk to get access to DynamoDB api. We are exporting two methods here:

  • getDbInstance
  • getDbClient

You can just live with using getDbInstance method. But using the getDbClient makes inserting plain javascript objects much easier. I will cover each individually.

Creating Tables

const dbCreateTable = async (collectionName) => {
  const dbClient = getDbInstance()

  return new Promise((resolve, reject) => {
    const onInsert = async function (err, data) {
      if (err) {
        console.error(err)
        reject()
      } else {
        console.log(`Create Table ${collectionName} succeeded`)
        resolve(0)
      }
    }
    const params = {
      TableName: collectionName,
      AttributeDefinitions: [
        {
          AttributeName: 'id',
          AttributeType: 'S'
        }
      ],
      KeySchema: [
        {
          AttributeName: 'id',
          KeyType: 'HASH'
        }
      ],
      ProvisionedThroughput: {
        ReadCapacityUnits: 1,
        WriteCapacityUnits: 1
      }
    }

    dbClient.createTable(params, onInsert)
  })
}

export default dbCreateTable

Note that we are getting the database instance using getDbInstance. This is because createTable is part of the core DynamoDB interface and is not avaiable as part of the DocumentClient.

Before you can start working with tables, you need to create table by specifing properties about the table attributes, partition key and provisioned throughput.

All of these are mandatory params attributes to be specified and cannot be empty:

  • AttributeDefinitions
  • KeySchema
  • ProvisionedThroughput

Introducing DocumentClient

Without using DocumentClient you need to format your Item by specifying the type of each attribute you want to insert. Following is a sample that you will need to pass to insert one item into the table.

var params = {
  TableName: 'CUSTOMER_LIST',
  Item: {
    'CUSTOMER_ID' : {N: '001'},
    'CUSTOMER_NAME' : {S: 'Richard Roe'}
  }
};

But this is an added overhead if you just want to deal with regular javascript objects.

With DocumentClient you can directly use javascript object instead as follows:

var params = {
  TableName: 'TABLE',
  Item: {
    'HASHKEY': VALUE,
    'CUSTOMER_ID': 001,
    'CUSTOMER_NAME': Richard Roe
  }
};

Official documentation: https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/dynamodb-example-document-client.html

Working with the single item

I have created the following method to stardardize the insertion process using getDbClient based put api.

const dbInsert = async ({ id, data, collectionTitle }) => {
  const dbClient = getDbClient()

  return new Promise((resolve, reject) => {
    const onInsert = async function (err, data) {
      if (err) {
        console.error(err)
        reject()
      } else {
        console.log('PutItem succeeded')
        resolve(0)
      }
    }
    const params = {
      TableName: collectionName,
      Item: {
        id: id,
        ...data
      }
    }

    dbClient.put(params, onInsert)
  })
}

export default dbInsert

You just pass the records to be inserted along with the table name and your are good.

await dbInsert(`123abc`, record, 'TABLE_NAME')

AWS Documentation: click here

Working with the batch

I have created the following method to stardardize the bulk insertion process using getDbClient based put api.

async function dbBulkInsert(records, collectionName) {
  const dbClient = getDbClient()

  return new Promise((resolve, reject) => {
    const onBatchWriteComplete = async function (err, data) {
      if (err) {
        console.error(err)
        reject()
      } else {
        console.log('PutItem succeeded')
        resolve(data)
      }
    }

    const params = {
      RequestItems: {
        [collectionName]: records
      }
    }
    dbClient.batchWrite(params, onBatchWriteComplete)
  })
}

export default dbBulkInsert

You just pass the records to be inserted along with the table name and your are good.

await dbBulkInsert(records, 'TABLE_NAME')

AWS Documentation: click here

Validating table creation and its content

Check tables list using cli:

aws dynamodb list-tables --endpoint-url http://localhost:8000

View table content using:

aws dynamodb scan \
    --table-name <insert-table-name-here> \
    --endpoint-url http://localhost:8000