こんにちは、ディベロップメントサービス1課の山本です。
初めてスプレー形式の日焼け止めを使ったのですが、うまく伸ばせずまだらに日焼けしてしまいました。太陽が憎い。
今回は DynamoDB JSON 形式データの変換方法について説明します。
低レベルAPI(client API)を利用されている方は必見です。
- この記事の対象者は?
- DynamoDB JSON 形式データとは
- 低レベルAPIと高レベルAPI
- 進め方
- 変換表
- DynamoDB サンプルテーブル
- DynamoDB JSON 形式 で頑張るパターン
- 標準 JSON 形式 の変換を活用するパターン
- まとめ
- さいごに
この記事の対象者は?
- DynamoDB JSON 形式データの処理に困っている人
- 高レベルAPI(resource API)から低レベルAPI(client API)に移行したい人
DynamoDB JSON 形式データとは
DynamoDB へ 低レベルAPI を利用してアクセスする際に、リクエスト・レスポンスにて利用される JSON 形式となります。
以下のように、データ型がキーとして追加されているのが特徴です。
DynamoDB 低レベル API - Amazon DynamoDB
{ "Item": { "Age": {"N": "8"}, "Colors": { "L": [ {"S": "White"}, {"S": "Brown"}, {"S": "Black"} ] }, "Name": {"S": "Fido"}, "Vaccinations": { "M": { "Rabies": { "L": [ {"S": "2009-03-17"}, {"S": "2011-09-21"}, {"S": "2014-07-08"} ] }, "Distemper": {"S": "2015-10-13"} } }, "Breed": {"S": "Beagle"}, "AnimalType": {"S": "Dog"} } }
低レベルAPIと高レベルAPI
低レベルAPIと高レベルAPIの違いを簡単にまとめました。
特徴 | クライアント(低レベル)API | リソースAPI |
---|---|---|
概要 | 下層のHTTP API操作との1対1のマッピングを提供 | 属性にアクセスしアクションを実行するためのリソースオブジェクトとコレクションを提供 |
boto3 | client API | resource API |
boto3 では resource API の更新が終了しているため、新規で利用する場合は client API を選択するのが良いでしょう。
The AWS Python SDK team does not intend to add new features to the resources interface in boto3. Existing interfaces will continue to operate during boto3’s lifecycle. Customers can find access to newer service features through the client interface.
Resources - Boto3 1.34.137 documentation
進め方
以下ドキュメントの内容に従って、変換用のコードを作成します。
Python と Boto3 による Amazon DynamoDB のプログラミング - Amazon DynamoDB
boto3 に用意されている TypeSerializer および TypeDeserializer クラスを使用して、標準 JSON と DynamoDB JSON を変換します。
boto3.dynamodb.types - Boto3 1.34.137 documentation
変換表
TypeSerializer と TypeDeserializer を用いることで、以下のようにデータの変換が可能です。
データ型 | DynamoDB JSON | 標準 JSON |
---|---|---|
NULL — Null | {'NULL': True} | None |
BOOL — ブール | {'BOOL': True/False} | True/False |
N — 数値 | {'N': str(value)} | Decimal(str(value)) |
S — 文字列 | {'S': string} | string |
B — バイナリ | {'B': bytes} | Binary(bytes) |
NS — 数値セット | {'NS': [str(value)]} | set([Decimal(str(value))]) |
SS — 文字列セット | {'SS': [string]} | set([string]) |
BS — バイナリセット | {'BS': [bytes]} | set([bytes]) |
L — リスト | {'L': list} | list |
M — マップ | {'M': dict} | dict |
DynamoDB サンプルテーブル
サンプルテーブルを作成しました。
こちらのデータを boto3 から取得します。
属性 | データ型 | 値の例 |
---|---|---|
id(PK) | N (数値) | 1 |
UserName | S (文字列) | John Doe |
IsPremiumUser | BOOL (ブール) | true |
ProfileImage | B (バイナリ) | "test" |
SubscriptionIDs | NS (数値セット) | ["1001", "1002", "1003"] |
Interests | SS (文字列セット) | ["photography", "cooking", "travel"] |
Documents | BS (バイナリセット) | ["test"] |
RecentOrders | L (リスト) | ["order1", "order2", "order3"] |
Preferences | M (マップ) | {"theme": "dark", "language": "en"} |
DynamoDB JSON 形式 で頑張るパターン
コード
get_item でキー名を指定する際に、とても面倒です。
import boto3 my_session = boto3.Session(profile_name='***') dynamodb = my_session.client('dynamodb') if __name__ == '__main__': key = {'id': {'N': '1'}} response = dynamodb.get_item( TableName='sample_table', Key=key ) print(response)
レスポンス
レスポンスもキーに型が入っており、非常に扱い辛いです。
{ "Preferences":{"M":{"theme": {"S": "dark"},"language": {"S": "en"}}}, "RecentOrders": {"L": [{"S": "order1"},{"S": "order2"},{"S": "order3"}]}, "IsPremiumUser": {"BOOL": True}, "Interests": {"SS": ["cooking", "photography", "travel"]}, "ProfileImage": {"B": b"\xb5\xeb-"}, "SubscriptionIDs": {"NS": ["1003", "1002", "1001"]}, "id": {"N": "1"}, "UserName": {"S": "John Doe"}, "Documents": {"BS": [b"\xb5\xeb-"]} }
標準 JSON 形式 の変換を活用するパターン
コード
DynamoDB JSON <->標準 JSON 形式 用の変換関数を2つ追加します。
リクエストパラメーター生成時と、レスポンス変換時に利用します。
import boto3 from boto3.dynamodb.types import TypeDeserializer, TypeSerializer my_session = boto3.Session(profile_name='***') dynamodb = my_session.client('dynamodb') def dynamo_to_python(dynamo_object: dict) -> dict: """DynamoDB JSON から 標準 JSON に変換する Args: dynamo_object (dict): DynamoDB JSON Returns: dict: 標準 JSON """ deserializer = TypeDeserializer() return { k: deserializer.deserialize(v) for k, v in dynamo_object.items() } def python_to_dynamo(python_object: dict) -> dict: """標準 JSON から DynamoDB JSON に変換する Args: python_object (dict): 標準 JSON Returns: dict: DynamoDB JSON """ serializer = TypeSerializer() return { k: serializer.serialize(v) for k, v in python_object.items() } if __name__ == '__main__': key = {"id": 1} # 標準 JSON で指定 # 標準 JSON から DynamoDB JSON へと変換 key = python_to_dynamo(key) response = dynamodb.get_item( TableName='sample_table', Key=key ) # DynamoDB JSON から 標準 JSON へと変換 response = dynamo_to_python(response['Item']) print(response)
レスポンス
キー名から型がなくなり、データ処理が抜群にやりやすくなりました。
{ "Preferences": {"theme": "dark","language": "en"}, "RecentOrders": ["order1","order2","order3"], "IsPremiumUser": True, "Interests": {"photography","cooking","travel"}, "ProfileImage": Binary(b"\xb5\xeb-"), "SubscriptionIDs": {Decimal("1001"), Decimal("1002"), Decimal("1003")}, "id": Decimal("1"), "UserName": "John Doe", "Documents": {Binary(b"\xb5\xeb-")} }
まとめ
- 低レベルAPI (boto3 だと client API)を利用する場合は、入出力が DynamoDB JSON 形式データ となる。
- boto3 の TypeSerializer と TypeDeserializer を使うことで、標準 JSONへの変換が可能
さいごに
都度["S"]とか["N"]とかつけるのは大変なので、変換して使いましょう。
本ブログがどなかたのお役に立てれば幸いです。