2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

DynamoDB を触ってみる

Posted at

初めに

この記事で DynamoDB について調べたので、せっかくなら触ってみる。

ローカル環境構築

version: '3.8'
services:
 dynamodb-local:
   command: "-jar DynamoDBLocal.jar -sharedDb -dbPath ./data"
   image: "amazon/dynamodb-local:latest"
   container_name: dynamodb-local
   ports:
     - "8000:8111" # 公式では 8000 ですが、port が被ってたので 8111
   volumes:
     - "./docker/dynamodb:/home/dynamodblocal/data"
   working_dir: /home/dynamodblocal

aws cli でアクセスできる

aws dynamodb list-tables --endpoint-url http://localhost:8111
{
    "TableNames": []
}

テーブル作成

X のような SNS を想定した次のような機能があるシステムを想定。

1. ユーザーのプロフィール管理

ユーザー名、メールアドレス、登録日などの基本情報を保存。
ユーザー間の友達リスト

2. 各ユーザーが持つ友達リストを保存。
投稿(ポスト)機能

3. ユーザーが投稿を作成する。
各投稿にはタイトル、本文、作成日時、いいね数が含まれる。
いいね(Likes)機能

4. 各投稿に対して他のユーザーが「いいね」できる。

image.png

テーブル定義の json を記載する

{
  "TableName": "ExampleSns",
  "AttributeDefinitions": [
    {
      "AttributeName": "PK",
      "AttributeType": "S"
    },
    {
      "AttributeName": "SK",
      "AttributeType": "S"
    }
  ],
  "KeySchema": [
    {
      "AttributeName": "PK",
      "KeyType": "HASH"
    },
    {
      "AttributeName": "SK",
      "KeyType": "RANGE"
    }
  ],
  "ProvisionedThroughput": {
    "ReadCapacityUnits": 5,
    "WriteCapacityUnits": 5
  },
  "GlobalSecondaryIndexes": [
    {
      "IndexName": "GSI1",
      "KeySchema": [
        {
          "AttributeName": "SK",
          "KeyType": "HASH"
        },
        {
          "AttributeName": "PK",
          "KeyType": "RANGE"
        }
      ],
      "Projection": {
        "ProjectionType": "ALL"
      },
      "ProvisionedThroughput": {
        "ReadCapacityUnits": 5,
        "WriteCapacityUnits": 5
      }
    }
  ]
}

  • TableName
    • テーブル名
  • AttributeDefinitions
    • テーブルとインデックスのキースキーマを記述する属性のリスト
    • AttributeType
      • N は数値、S は文字列、B はバイナリ
  • KeySchema
    • "KeyType": "HASH" ... パーティションキー
    • "KeyType": "RANGE" ... ソートキー
  • ProvisionedThroughput
    • RCU
    • WCU
  • GlobalSecondaryIndex
    • グローバルセカンダリーインデックスの定義
  • IndexName
    • インデックス名
  • KeySchema
    • インデックスが使用するキーを定義
    • GSI は同じデータでもう1つ別のテーブルを作成するようなイメージ
    • SK に GSI を設定することは必須でもなんでもないが、設定するケースは多そうかも?
    • 例えば、投稿日時(SK)でソートされた投稿を取得するようなクエリが実行可能になったりするらしい
  • ProjectionType
  • ProvisionedThroughput
    • GSI の読み取り・書き込みキャパシティユニットを設定
    • キャパシティユニットはテーブル、インデックスごとに設定する必要があるらしい

テーブル作成

aws dynamodb create-table \
    --cli-input-json file://table-definition.json \
    --endpoint-url http://localhost:8111

作成したテーブルの確認

aws dynamodb list-tables --endpoint-url http://localhost:8111

結果

{
    "TableNames": [
        "ExampleSns"
    ]
}

データの新規追加

aws dynamodb put-item \
    --table-name ExampleSns \
    --item '{
        "PK": {"S": "user#123"},
        "SK": {"S": "profile"},
        "name": {"S": "A-san"},
        "email": {"S": "a-san@example.com"},
        "joined_at": {"S": "2024-01-01"}
    }' \
    --endpoint-url http://localhost:8111

バッチ

一度に複数のクエリをまとめて投げることも可能。

ネットワークコールの回数を減らし効率化できる。

バッチを使った更新 batch-write-item

batch-write-item

BatchWriteItem操作は、最大25個のPutItemまたはDeleteItem要求を一度に処理できる。

aws dynamodb batch-write-item \
    --request-items '{
        "ExampleSns": [
            {
                "PutRequest": {
                    "Item": {
                        "PK": {"S": "user#123"},
                        "SK": {"S": "post#2024-12-25T10:00"},
                        "content": {"S": "Merry Christmas!"},
                        "likes": {"N": "0"},
                        "comments": {"N": "0"}
                    }
                }
            },
            {
                "PutRequest": {
                    "Item": {
                        "PK": {"S": "user#123"},
                        "SK": {"S": "following#789"},
                        "followed_user_id": {"S": "user#789"},
                        "followed_at": {"S": "2024-12-24T09:00"}
                    }
                }
            },
            {
                "PutRequest": {
                    "Item": {
                        "PK": {"S": "user#789"},
                        "SK": {"S": "profile"},
                        "name": {"S": "B-san"},
                        "email": {"S": "b-san@example.com"},
                        "joined_at": {"S": "2023-01-01"}
                    }
                }
            }
        ]
    }' \
    --endpoint-url http://localhost:8111

結果

{
    "UnprocessedItems": {}
}

バッチ処理はトランザクション処理ではないので、1つのクエリだけ失敗する場合もある。

UnprocessedItems に失敗したデータが入るらしいので、アプリケーション側での制御が必要。

データを読み込む

query コマンド

ここではユーザーの profile 情報を取得する。

aws dynamodb query \
    --table-name ExampleSns \
    --key-condition-expression "PK = :userId AND SK = :sortKeyValue" \
    --expression-attribute-values '{":userId": {"S": "user#123"}, ":sortKeyValue": {"S": "profile"}}' \
    --endpoint-url http://localhost:8111

(AttributeName を PK, SK にしたせいでちょっとわかりにくくなってしまった...)

  • --table-name
    • ExampleSns テーブルが検索対象
  • --key-condition-expression
    • 検索条件
      • PK (パーティションキーにつけている名前)の値が :userId
      • かつ
      • SK (ソートキーにつけている名前)の値が sortKeyValue
  • --expression-attribute-values
    • 検索する値
      • :userId に文字列 user#123 を代入
      • :sortKeyValue に文字列 profile を代入
  • --endpoint-url
    • エンドポイント URL

結果

{
    "Items": [
        {
            "SK": {
                "S": "profile"
            },
            "name": {
                "S": "A-san"
            },
            "joined_at": {
                "S": "2024-01-01"
            },
            "PK": {
                "S": "user#123"
            },
            "email": {
                "S": "a-san@example.com"
            }
        }
    ],
    "Count": 1,
    "ScannedCount": 1,
    "ConsumedCapacity": null
}

scan コマンド

特定のパーティションキーに依存しない全件取得。
取得が遅くなる。RCU の消費が大きくなるため基本的には使用しないのが無難。

aws dynamodb scan \
    --table-name ExampleSns \
    --endpoint-url http://localhost:8111

結果

{
    "Items": [
        {
            "SK": {
                "S": "profile"
            },
            "name": {
                "S": "A-san"
            },
            "joined_at": {
                "S": "2024-01-01"
            },
            "PK": {
                "S": "user#123"
            },
            "email": {
                "S": "a-san@example.com"
            }
        }
    ],
    "Count": 1,
    "ScannedCount": 1,
    "ConsumedCapacity": null
}

バッチを使った取得処理 batch-get-item

aws dynamodb batch-get-item \
    --request-items '{
        "ExampleSns": {
            "Keys": [
                {"PK": {"S": "user#123"}, "SK": {"S": "post#2024-12-25T10:00"}},
                {"PK": {"S": "user#123"}, "SK": {"S": "following#789"}},
                {"PK": {"S": "user#789"}, "SK": {"S": "profile"}}
            ]
        }
    }' \
    --endpoint-url http://localhost:8111

GSIを利用した検索も可能

aws dynamodb query \
    --table-name ExampleSns \
    --index-name GSI1 \
    --key-condition-expression "SK = :sk" \
    --expression-attribute-values '{
        ":sk": {"S": "post#2024-12-25T10:00"}
    }' \
    --endpoint-url http://localhost:8111

データの更新

UpdateItem

投稿のいいねを増やす

aws dynamodb update-item \
    --table-name ExampleSns \
    --key '{"PK": {"S": "user#123"}, "SK": {"S": "post#2024-12-25T10:00"}}' \
    --update-expression "SET likes = likes + :inc" \
    --expression-attribute-values '{":inc": {"N": "1"}}' \
    --endpoint-url http://localhost:8111
  • 対象キー (PK, SK): user#123 の投稿 post#2024-12-25T10:00
  • 更新内容: likes 属性を +1
  • 単一アイテムに対しての簡単な更新操作

トランザクションを利用した更新処理 TransactWriteItems

aws dynamodb transact-write-items \
    --transact-items '[
        {
            "Update": {
                "TableName": "ExampleSns",
                "Key": {
                    "PK": {"S": "user#123"},
                    "SK": {"S": "profile"}
                },
                "UpdateExpression": "SET email = :email",
                "ExpressionAttributeValues": {":email": {"S": "hoge@example.com"}}
            }
        },
        {
            "Update": {
                "TableName": "ExampleSns",
                "Key": {
                    "PK": {"S": "user#123"},
                    "SK": {"S": "post#2024-12-25T10:00"}
                },
                "UpdateExpression": "SET likes = likes + :inc",
                "ExpressionAttributeValues": {":inc": {"N": "1"}}
            }
        }
    ]' \
    --endpoint-url http://localhost:8111


データの削除

aws dynamodb delete-item \
    --table-name ExampleSns \
    --key '{"PK": {"S": "user#123"}, "SK": {"S": "post#2024-12-25T10:00"}}' \
    --endpoint-url http://localhost:8111

条件つきの削除

いいね が 0 件の場合のみ削除する

aws dynamodb delete-item \
    --table-name ExampleSns \
    --key '{"PK": {"S": "user#123"}, "SK": {"S": "post#2024-12-25T10:00"}}' \
    --condition-expression "likes = :zero" \
    --expression-attribute-values '{":zero": {"N": "0"}}' \
    --endpoint-url http://localhost:8111

2
0
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
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?