AWS SDKでDynamoDBを操作(挿入, 取得, 更新, 削除)

AWS SDKを利用してDynamoDBを操作する方法について確認します。「テーブル作成・削除」「アイテムの挿入・取得・更新・削除」について取り上げます。

目次

aws-sdkをインストール

aws-sdk をインストールします。

yarn add aws-sdk

AWS.DynamoDB

Table作成|createTable

usersテーブル を作成します。

const AWS = require('aws-sdk')
AWS.config.loadFromPath('./config.json')
const dynamoDB = new AWS.DynamoDB()

const params = {
  TableName: 'users',
  AttributeDefinitions: [
    { AttributeName: 'user_id', AttributeType: 'N' },     // number
    { AttributeName: 'created_at', AttributeType: 'S' },  // string
    { AttributeName: 'post_id', AttributeType: 'N' }      // number
  ],
  KeySchema: [
    { AttributeName: 'user_id', KeyType: 'HASH' },     // Partition key
    { AttributeName: 'created_at', KeyType: 'RANGE' }  // Sort key
  ],
  LocalSecondaryIndexes: [
    {
      IndexName: 'post_local_index',
      Projection: {
        ProjectionType: 'ALL' // 射影される属性 > 全て
      },
      KeySchema: [
        { AttributeName: 'user_id', KeyType: 'HASH' },
        { AttributeName: 'post_id', KeyType: 'RANGE' }
      ]
    }
  ],
  GlobalSecondaryIndexes: [
    {
      IndexName: 'post_global_index',
      Projection: {
        ProjectionType: 'ALL'
      },
      KeySchema: [
        { AttributeName: 'post_id', KeyType: 'HASH' }
      ],
      ProvisionedThroughput: {
        ReadCapacityUnits: 10,
        WriteCapacityUnits: 10
      }
    }
  ],
  ProvisionedThroughput: {
    ReadCapacityUnits: 10,
    WriteCapacityUnits: 10
  }
}

dynamoDB.createTable(params, (err, data) => {
  if (err) {
    console.error('Unable to create table. Error JSON:', JSON.stringify(err, null, 2))
  } else {
    console.log('Created table. Table description JSON:', JSON.stringify(data, null, 2))
  }
})

以下、上記処理を実行して生成されたテーブルです。

認証方法について

ここでは、動作確認したいだけなので、 AWS.config.loadFromPath で認証情報を設定しています。実際に利用する場合は、下記ページを参考に推奨順序の高い認証方法で実装することをお勧めします。

https://docs.aws.amazon.com/ja_jp/sdk-for-javascript/v2/developer-guide/setting-credentials-node.html

Table削除|deleteTable

usersテーブル を削除します。

const AWS = require('aws-sdk')
AWS.config.loadFromPath('./config.json')

const dynamoDB = new AWS.DynamoDB()
const params = { TableName: 'users' }
dynamoDB.deleteTable(params, (err, data) => {
  if (err) {
    console.error('Unable to delete table. Error JSON:', JSON.stringify(err, null, 2))
  } else {
    console.log('Deleted table. Table description JSON:', JSON.stringify(data, null, 2))
  }
})
$ node delete-table.js 
Deleted table. Table description JSON: {
  "TableDescription": {
    "TableName": "users",
    "TableStatus": "DELETING",
    "ProvisionedThroughput": {
      "NumberOfDecreasesToday": 0,
      "ReadCapacityUnits": 10,
      "WriteCapacityUnits": 10
    },
    "TableSizeBytes": 0,
    "ItemCount": 0,
    "TableArn": "arn:aws:dynamodb:ap-northeast-1:XXXXXXXXXXXX:table/users",
    "TableId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
  }
}

AWS.DynamoDB.DocumentClient

Item挿入|put

const AWS = require('aws-sdk')
AWS.config.loadFromPath('./config.json')
const documentClient = new AWS.DynamoDB.DocumentClient()

items = [
  { user_id: 1, post_id: 2, created_at: '1544741492', message: 'aaaaaaaaaaaaaa' },
  { user_id: 2, post_id: 9, created_at: '1544745092', message: 'bbbbbbbbbbbbbb' },
  { user_id: 3, post_id: 3, created_at: '1544748692', message: 'cccccccccccccc' },
  { user_id: 1, post_id: 5, created_at: '1544752292', message: 'dddddddddddddd' },
  { user_id: 5, post_id: 3, created_at: '1544755892', message: 'eeeeeeeeeeeeee' },
]

items.forEach(item => {
  const params = {
    TableName: 'users',
    Item: {
      'user_id': item.user_id,
      'post_id': item.post_id,
      'created_at': item.created_at,
      'message': item.message
    }
  }
  documentClient.put(params, (err, data) => {
    if (err) console.log(err)
    else console.log(data)
  })
})
$ node put.js 
{}
{}
{}
{}
{}

5項目追加されました。

単一Item取得|get

const AWS = require('aws-sdk')
AWS.config.loadFromPath('./config.json')
const documentClient = new AWS.DynamoDB.DocumentClient()

const params = {
  TableName: 'users',
  Key: {
    'user_id': 1,
    'created_at': '1544752292'
  }
}
documentClient.get(params, (err, data) => {
  if (err) console.log(JSON.stringify(err, null, 2))
  else console.log(JSON.stringify(data, null, 2))
})
$ node get.js 
{
  "Item": {
    "message": "dddddddddddddd",
    "user_id": 1,
    "created_at": "1544752292",
    "post_id": 5
  }
}

条件に一致するItem取得|query

const AWS = require('aws-sdk')
AWS.config.loadFromPath('./config.json')
const documentClient = new AWS.DynamoDB.DocumentClient()

const params = {
  TableName: 'users',
  KeyConditionExpression: 'user_id = :user_id and created_at >= :created_at',
  ExpressionAttributeValues: {
    ':user_id': 1,
    ':created_at': '1544752292'
  }
}
documentClient.query(params, (err, data) => {
  if (err) console.log(JSON.stringify(err, null, 2))
  else console.log(JSON.stringify(data, null, 2))
})
$ node query.js 
{
  "Items": [
    {
      "message": "dddddddddddddd",
      "user_id": 1,
      "created_at": "1544752292",
      "post_id": 5
    }
  ],
  "Count": 1,
  "ScannedCount": 1
}

条件に一致するItem取得|scan

const AWS = require('aws-sdk')
AWS.config.loadFromPath('./config.json')
const documentClient = new AWS.DynamoDB.DocumentClient()

const params = {
  TableName: 'users',
  FilterExpression: 'message = :message',
  ExpressionAttributeValues: { ':message': 'cccccccccccccc' }
}
documentClient.scan(params, (err, data) => {
  if (err) console.log(JSON.stringify(err, null, 2))
  else console.log(JSON.stringify(data, null, 2))
})
$ node scan.js 
{
  "Items": [
    {
      "message": "cccccccccccccc",
      "user_id": 3,
      "created_at": "1544748692",
      "post_id": 3
    }
  ],
  "Count": 1,
  "ScannedCount": 5
}

全Item取得|scan

Query Scan の結果セットにはデータ制限( 1MB )があるので、注意が必要です。全件取得したつもりが、データ制限により 1MB 分のitemしか取得されていなかったという意図しない動作が発生しうります。

データ制限を越えると、クエリ応答LastEvaluatedKey がセットされます。 以下実装では、LastEvaluatedKey が設定されている間、繰り返しscanをして全item取得しています。

const AWS = require('aws-sdk')
AWS.config.loadFromPath('./config.json')
const documentClient = new AWS.DynamoDB.DocumentClient()

const scanAll = async () => {
  let params = {
    TableName: 'users',
  }
  let items = []

  const scan = async () => {
    console.log('execute scan')
    console.log(params)
    const result = await documentClient.scan(params).promise()
    items.push(...result.Items)

    if (result.LastEvaluatedKey) {
      params.ExclusiveStartKey = result.LastEvaluatedKey
      await scan()
    }
  }

  try {
    await scan()
    return items
  } catch (err) {
    console.error(`[Error]: ${JSON.stringify(err)}`)
    return err
  }
}

(async () => {
  const items = await scanAll()
})()
$ node scanAll.js 
execute scan
{ TableName: 'users' }
execute scan
{ TableName: 'users',
  ExclusiveStartKey: { user_id: 9, created_at: '1544741492' } }
execute scan
{ TableName: 'users',
  ExclusiveStartKey: { user_id: 5, created_at: '1544741492' } }

Item更新|update

const AWS = require('aws-sdk')
AWS.config.loadFromPath('./config.json')
const documentClient = new AWS.DynamoDB.DocumentClient()

const params = {
  TableName: 'users',
  Key: {
    user_id: 3,
    created_at: '1544748692'
  },
  UpdateExpression: 'set message = :message, post_id=:post_id',
  ExpressionAttributeValues: {
    ':message': 'update_xxxxxxxxxxxxxxx',
    ':post_id': 100
  },
  ReturnValues: 'ALL_NEW'
}
documentClient.update(params, (err, data) => {
  if (err) console.log(JSON.stringify(err, null, 2))
  else console.log(JSON.stringify(data, null, 2))
})
$ node update.js 
{
  "Attributes": {
    "message": "update_xxxxxxxxxxxxxxx",
    "user_id": 3,
    "created_at": "1544748692",
    "post_id": 100
  }
}

Item削除|delete

const AWS = require('aws-sdk')
AWS.config.loadFromPath('./config.json')
const documentClient = new AWS.DynamoDB.DocumentClient()

const params = {
  TableName: 'users',
  Key: {
    user_id: 1,
    created_at: '1544752292'
  }
}
documentClient.delete(params, (err, data) => {
  if (err) console.log(JSON.stringify(err, null, 2))
  else console.log(JSON.stringify(data, null, 2))
})
$ node delete.js 
{}

参考

よかったらシェアしてね!
目次