Python3の対話シェル上でDynamoDBのアイテムを読み書き削除する

Pythonと `boto3` によるAmazon DynamoDBのアイテムの読み書きを、対話型シェル上でステップバイステップで実行してみました。

# 前提

* APIアクセス用の認証情報がAWS CLIで[デフォルトプロファイル](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-chap-configure.html#cli-quick-configuration)または[名前付きプロファイル](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-chap-configure.html#cli-quick-configuration-multi-profiles)に格納されていること
* Pythonがインストールされていること（ここでは[Anaconda 2020.02 for Windows Installer](https://www.anaconda.com/distribution/)を使用しました）
* [boto3](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html#installation)がインストールされていること

# 手順

1. [Boto3（AWS SDK for Python）](https://aws.amazon.com/jp/sdk-for-python/)のインポート
2. DynamoDBクライアントの生成
3. DynamoDBリソースの生成
4. Tableリソースの生成
5. テーブルへのアイテム追加
6. テーブルからのアイテム取得
7. テーブルからのアイテム削除
8. バッチ処理でのテーブルへのアイテム追加

# 実行

`boto3` をインポートし[DynamoDBクライアントを生成](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#client)します。またレコードの書き込みに便利なので、[DinamoDBリソースも生成](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#service-resource)します。デフォルトプロファイルを使うときは、2行目は `client = boto3.client("dynamodb")` 、3行目は `dynamodb = boto3.resource("dynamodb")` です。です。

~~~
>>> import boto3
>>> client = boto3.session.Session(profile_name="tachallenge").client('dynamodb')
>>> dynamodb = boto3.session.Session(profile_name="tachallenge").resource('dynamodb')
~~~

まず[`client.list_tables()`](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#DynamoDB.Client.list_tables)でテーブルを取得しテーブル名を確認。テーブル名がリストで格納されているのを確認します。

~~~
>>> tables = client.list_tables()
>>> tables["TableNames"]
~~~

レコードの操作はDynamoDBリソースのサブリソースであるテーブルリソースを取得して、これを使うことにします。ここでは、取得したテーブル名の先頭のものを使うことにします。

~~~
>>> table = dynamodb.Table(tables["TableNames"][0])
~~~

[`Table.put_item()`](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#DynamoDB.Table.put_item)でアイテムを追加します。 `Item` に追加したいデータを格納した辞書型で渡します。これにはキーが含まれていなければいけません。例えば `ID` がプライマリキーになっているとしたら、以下はうまくアイテムを追加できます。

~~~
>>> result = table.put_item(Item = {'ID': '1002', 'Attirbute1': 'Value1', 'Attirbute2': 'Value2', ...})
~~~

[`Table.get_item()`](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#DynamoDB.Table.get_item)でアイテムを取得します。 `Key` でアイテムを特定するためのキー項目とその値を指定します。

~~~
>>> item = table.get_item(Key={'ID': '1002'})
>>> item["Item"]
~~~

[`Table.delete_item()`](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#DynamoDB.Table.delete_item)でアイテムを削除します。 `Key` でアイテムを特定するためのキー項目とその値を指定します。

~~~
>>> result = table.delete_item(Key={'ID': '1002'})
>>> result
~~~

[`Table.batch_writer()`](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#DynamoDB.Table.batch_writer)を使うと、アイテムの追加や削除を複数件行う際、自動的にバッファリング、送信、再送を行ってくれるようです。

> This method creates a context manager for writing objects to Amazon DynamoDB in batch.
> The batch writer will automatically handle buffering and sending items in batches. In addition, the batch writer will also automatically handle any unprocessed items and resend them as needed. All you need to do is call put_item for any items you want to add, and delete_item for any items you want to delete.

以下のように使用します。

~~~
>>> with table.batch_writer() as batch:
...   batch.put_item(Item = {'ID': '1002'})
...   batch.put_item(Item = {'ID': '1003'})
...   batch.put_item(Item = {'ID': '1004'})
...
~~~

with句を抜けた時点で、テーブル上に各アイテムが作成されます。

# まとめ

「DynamoDBのアイテムをちょっと確認したい」「スクリプト化する前にステップバイステップで`boto3`でのアクセス手順を確認してみたい」というタイミングがあったので、Pythonの対話型シェルでのDynamoDBのアイテムの読み書きと削除手順を確認、まとめてみました。

# 参考

主に以下を参考にしました。

* [AWS SDK for Python | AWS](https://aws.amazon.com/jp/sdk-for-python/)
* [Quickstart — Boto 3 Docs 1.12.20 documentation](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html)
* [DynamoDB — Boto 3 Docs 1.12.21 documentation](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html)

----
本ページ内容は筆者が参照の便のためにある時点でまとめた個人的なメモです。内容を保証するものではなく、また筆者の所属組織等とは一切かかわりがありません。