Amazon DynamoDB独自のJSONデータ型「データ型記述子」についてまとめてみた

Amazon DynamoDB独自のJSONデータ型「データ型記述子」についてまとめてみた

Amazon DynamoDBに保存されるデータ型は、通常のJSON形式ではなく、データ型記述子という形式です。実際にアプリケーションなどでDynamoDBのデータを使用する場合は、データ型記述子から通常のJSONに型変換を行うことも多いです。
Clock Icon2024.08.07

Amazon DynamoDBのデータの型が通常のJSONではない?

おのやんです。

みなさん、Amazon DynamoDB(以下、DynamoDB)に保存されているデータのJSON形式が独特なものになっていると思ったことはありませんか?私はあります。

DynamoDBに保存されているデータをJSONで表示しようとしたとき、「DynamoDB JSON の表示」のトグルがオンになっている状態で見て、通常のJSONとは違うデータ型で保存されていることに気づくと思います。

dynamodb_json

このデータ型は、DynamoDBの内部で使用される独自のものとなっています。最初見た時は戸惑いましたが、データ形式さえ押さえてしまえばなんてことはないデータなので、今回はDynamoDBのJSONデータ型についてまとめたいと思います。

データ型記述子

DynamoDBでは、JSONのデータを独自の形式で保存しており、この形式のことをデータ型記述子と呼びます

データ型記述子は、各属性を解釈する方法を DynamoDB に伝えるトークンです。

https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/Programming.LowLevelAPI.html#Programming.LowLevelAPI.DataTypeDescriptors

DynamoDBでデータを扱うときは、通常のJSONデータがデータ型記述子に変換されています。

例として、以下のJSONデータをDynamoDBに保存するケースを考えます。

{
 "companyId": "COMP123",
 "userId": "USER456",
 "address": {
  "city": "Anytown",
  "state": "CA",
  "street": "123 Main St",
  "zipCode": "12345"
 },
 "age": 30,
 "departments": [
  "HR",
  "Finance"
 ],
 "email": "john.doe@example.com",
 "firstName": "John",
 "isActive": true,
 "lastLogin": "2023-05-15T14:30:00Z",
 "lastName": "Doe",
 "projects": [
  "Project A",
  "Project B",
  "Project C"
 ],
 "salary": 75000.5
}

DynamoDBに上記のJSONデータを保存する際は、データ型記述子に変換されます。以下の例を見てもらうとわかる通り、各値の部分にSNなどの文字が付与されているのがわかります。この記号によって、各値がDynamoDBでどう扱われるかが決定されます。

{
 "companyId": {
  "S": "COMP123"
 },
 "userId": {
  "S": "USER456"
 },
 "address": {
  "M": {
   "city": {
    "S": "Anytown"
   },
   "state": {
    "S": "CA"
   },
   "street": {
    "S": "123 Main St"
   },
   "zipCode": {
    "S": "12345"
   }
  }
 },
 "age": {
  "N": "30"
 },
 "departments": {
  "L": [
   {
    "S": "HR"
   },
   {
    "S": "Finance"
   }
  ]
 },
 "email": {
  "S": "john.doe@example.com"
 },
 "firstName": {
  "S": "John"
 },
 "isActive": {
  "BOOL": true
 },
 "lastLogin": {
  "S": "2023-05-15T14:30:00Z"
 },
 "lastName": {
  "S": "Doe"
 },
 "projects": {
  "L": [
   {
    "S": "Project A"
   },
   {
    "S": "Project B"
   },
   {
    "S": "Project C"
   }
  ]
 },
 "salary": {
  "N": "75000.5"
 }
}

試しにマネジメントコンソール上から確認してみると、上記のデータはこのように解釈されていました。

json_data_on_dynamodb

DynamoDBのJSONでは、各記号にそれぞれ以下のような意味があります。

記号 意味 サンプル値(DynamoDB JSON) サンプル値(JSON) 備考
S 文字列 {"S": "COMP123"} "COMP123"
N 数値 {"N": "30"} 30
B バイナリ {"B": "SGVsbG8="} 変換不可 リクエスト送信時にbase64への変換が必要
BOOL ブール {"BOOL": true} true
NULL Null {"NULL": true} null
M マップ {"M": {"city" :{"S": "Anytown"}}} {"city": "Anytown"}
L リスト {"L": [{"S": "HR"}, {"S": "Finance"}]}` `["HR", "Finance"]
SS 文字列セット {"SS": ["Red", "Green", "Blue"]}` `["Red", "Green", "Blue"]
NS 数値セット {"NS": ["1.1", "2.2", "3.3"]} [1.1, 2.2, 3.3]
BS バイナリセット {"BS": ["AAECAwQFBg==", "BwgJCgsMDQ==", "Dg8QERITFA=="]} 変換不可 リクエスト送信時にbase64への変換が必要

DynamoDBから取得してみた

こちらのデータを実際に取得すると、どのような形式のなるのか、検証してみました。

AWS CLIでデータを取得した場合、保存されているデータの形式(Itemsの要素の形式)はDyanmoDB JSONになります。

$ aws dynamodb scan --table-name aws-test-dynamodb-table
{
    "Items": [
        {
            "companyId": {
                "S": "COMP123"
            },
            "lastName": {
                "S": "Doe"
            },

            ...

            "age": {
                "N": "30"
            }
        }
    ],
    "Count": 1,
    "ScannedCount": 1,
    "ConsumedCapacity": null
}

boto3上でも取得してみます。サンプルとして、DynamoDBからテーブル内のデータを1件だけ取ってくる以下のコードを作成します。

sample.py
import boto3
import json

def scan_and_display_dynamodb_item():
    # DynamoDBクライアントを作成
    dynamodb = boto3.client("dynamodb")

    # テーブルをスキャン
    response = dynamodb.scan(
        TableName="aws-test-dynamodb-table",
        Limit=1
    )

    # 結果を取得
    items = response.get("Items",[])
    print("Item found in the table:")
    item = items[0]
    print(item)

scan_and_display_dynamodb_item()

こちらを実行してみると、先ほどと同じようにDynamoDB JSONの形式で取得されることがわかります。

$ python3 sample.py 
Item found in the table:
{'companyId': {'S': 'COMP123'}, 'lastName': {'S': 'Doe'}, 'projects': {'L': [{'S': 'Project A'}, {'S': 'Project B'}, {'S': 'Project C'}]}, 'salary': {'N': '75000.5'}, 'address': {'M': {'zipCode': {'S': '12345'}, 'state': {'S': 'CA'}, 'city': {'S': 'Anytown'}, 'street': {'S': '123 Main St'}}}, 'departments': {'L': [{'S': 'HR'}, {'S': 'Finance'}]}, 'email': {'S': 'john.doe@example.com'}, 'firstName': {'S': 'John'}, 'lastLogin': {'S': '2023-05-15T14:30:00Z'}, 'isActive': {'BOOL': True}, 'userId': {'S': 'USER456'}, 'binary': {'B': b'\x00\x00'}, 'age': {'N': '30'}}

実際にアプリケーション上でDynamoDBのデータを利用する場合は、JSON形式に型変換を行うことが多いです。JSONの型変換については、以下のブログにまとまっていますので、こちらを参考にしていただければと思います。

https://dev.classmethod.jp/articles/convert-dynamodb-json-to-python-dict-by-boto3/

https://dev.classmethod.jp/articles/js-dynamodb-json-marshall-unmarshall/

DynamoDBでは独自のJSONデータ形式を採用している

以上、DynamoDB上で扱っているJSONデータの形式についてまとめてみました。アプリケーション上でDynamoDBのデータを使用する場合は、ライブラリなどで型変換などのステップを踏むことが多いため、意外と大変だったりします。

DynamoDBのJSONデータについてわからなくなったら、本ブログを参考にしていただければと思います。では!

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.