5
1

More than 3 years have passed since last update.

LambdaでDynamoDBに複数レコードの書き込みをする(Python、JavaScript)

Last updated at Posted at 2020-09-11

はじめに

DynamoDBに複数レコードを書き込み(更新)する必要があったので、実装してみた結果と注意的なものを書き留めたいと思い記事を投稿した
またPythonとNode.jsの両方での実装を載せようと思います

前提

テーブル

今回書き込みをするテーブルは以下を想定
テーブル名:Users
カラムと型(スキーマ自体に型はありませんが、登録するデータの型として便宜上決めておきます)は以下の通り

  • id(primary key):Number
  • name:String
  • address:String
  • friends: List[Map]

friendはid, name, addressのキーを持つMapの一覧を想定
今回は複雑めな型(Userテーブルのfriendのような型)であっても、書き込みができることも示しておきたいことの一つなので、そもそもテーブルの設計がベストであるかは一旦無視でいきます

Lambdaの準備

今回はLambda上で動くコードを掲載するので、Lambdaは各自で準備ができていることを前提とします

記事の流れ

全体のコード例 → 軽い解説
の手順で書いていき、最後に共通する補足事項を載せる

Pythonでの実装

import boto3
from boto3.dynamodb.conditions import Key

def update_users(table, users_friends):
   with table.batch_writer() as batch:
      for n in range(3):
        batch.put_item(
          Item={
                "id": n + 1,
                "name": "user" + str(n + 1),
                "address": "address" + str(n + 1),
                "friends": users_friends[n]
          }
        )

def lambda_handler(event, context):
  try:
    dynamoDB = boto3.resource("dynamodb")
    table = dynamoDB.Table("Users")
      user1_friends = [
        { "id": 2, "name": "user2", "address": "address2" },
        { "id": 3, "name": "user3", "address": "address3" }
      ]
      user2_friends = [
        { "id": 1, "name": "user1", "address": "address1" },
        { "id": 3, "name": "user3", "address": "address3" }
      ]
      user3_friends = [
        { "id": 1, "name": "user1", "address": "address1" },
        { "id": 2, "name": "user2", "address": "address2" }
      ]

      users_friends = [user1_friends, user2_friends, user3_friends]

    update_users(table, users_friends)

    return event["message"] # 返すものは適当
  except Exception as e:
        print(e)

軽く解説

コードの書き方云々や書き込むデータ自体については本質ではないので、スルーしてもらって大丈夫です
大事なのはupdate_users関数の中身で、DynamoDBのモデルのインスタンスに生えているbatch_writeメソッドを使っているということ
すなわち、複数書き込みをしたいときは以下のブロック内でPUTをする

with table.batch_write() as batch:
    # ...略

また、PUTする際には例でいうとbatch.put_itemを呼び出してやる
こいつのItemという名前の引数に書き込みの内容を記述していく
そしてもう一点注目したいのが、List[Map]という型であっても問題なく書き込むことができるという点
基本的にどんな型でも指定したキーの値としてちゃんとDBに書き込めるので、要するにItemには更新したい辞書をそのまま渡してあげれば問題ない
最後にちょっとした補足として、batch_writeのブロック内でfor文を回しているが、当然batch.put_itemをベタで複数回書いていってもよいので、もしfor文では書けないときはベタでやればいい
また、一度にできる書き込める上限は25件までと言われているが、どうやら25件以上の場合は再送してくれたりよしなにやってくれているらしいので、件数を気にせずコードを書いていけるっぽい

Node.jsでの実装

const AWS = require("aws-sdk");
const dynamoDB = new AWS.DynamoDB.DocumentClient({
  region: "ap-northeast-1"
});

const tableName = "Users";

exports.handler = (event, context) => {
      const user1Friends = [
        { id: 2, name: "user2", address: "address2" },
        { id: 3, name: "user3", address: "address3" }
      ];
      const user2Friends = [
        { id: 1, name: "user1", address: "address1" },
        { id: 3, name: "user3", address: "address3" }
      ];
      const user3Friends = [
        { id: 1, name: "user1", address: "address1" },
        { id: 2, name: "user2", address: "address2" }
      ];
      const usersFriends = [user1Friends, user2Friends, user3Friends]

    const params = {
        RequestItems: {
          [tableName]: usersFriends.map((e, i) => ({
            PutRequest: {
              Item: {
                id: i + 1,
                name: `user${i + 1}`,
                address: `address${i + 1}`,
                friends: e
              }
            }
          }))
        }
      };

// callbackは適当
    dynamoDB.batchWrite(params, (e, data) => {
        if (e) {
          context.fail(e);
        } else {
          context.succeed(data);
        }
    });
};

軽い解説

Pythonでの解説で述べたようにコードやデータの値そのものに関してはスルー
ここで大事なのはAWS.DynamoDB.DocumentClientにあるbatchWriteというプロパティ(関数)
こいつの引数は結構癖があるのでClass: AWS.DynamoDB.DocumentClient — AWS SDK for JavaScriptを参照してください
Node.jsでの複数書き込みについて調べたときによく出てくるのはbatchWriteItemだったのですが、現在(2020年9月時点)のLambdaで用意されている最新のNode.jsの実行環境だとどうやらないっぽいので、動かず意外と手こずる
batchWriteItemとの大きな違いはItemのオブジェクトがDynamoDB特有の型付きのオブジェクト(name: { "S": "user" }みたいなやつ)である必要がなくなっている点
要するに書き込みたい値を気にせずそのままJSONにしてItemの値として渡せば問題なく動く
そのため、当然Map[List]という複雑な型であってもそのまま渡せば書き込み可能です

全体の補足

バッチ処理で更新(update)をしたいときはPUTを使うしかない
理由は単純でUPDATEがないからで、仕方ないので地道にPUTで記述していく必要がある
またバッチ処理内ではDELETEをすることができるので、今回はフォーカスしませんでしたが、一応あるということだけ言っておきます・・・

おわりに

いかがでしたでしょうか
複数操作についてはコードと1, 2行程度の解説がある記事はちょこちょこ見かけますが、書き込みに特化して解説されているのはあまり見かけず(あっても複雑な型でもできるのか不明であったり、そもそも実行時エラーになってしまう)、多少やってて手こずったので、備忘の意味も兼ねて書き残してみました
若干ニッチな分野かもしれないですが、少しでも役に立てて貰えれば幸いです

参考

Amazon DynamoDB — Boto3 Docs 1.14.56 documentation
Class: AWS.DynamoDB.DocumentClient — AWS SDK for JavaScript

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1