DynamoDBメモ

AWS

こんにちは。ユウです。

Pythonを使ったDynamoDBの操作方法について知識の定着のため、まとめておきます。

本記事のサンプルコードは以下のバージョンで動作することを確認しています。

項目バージョン
Python3.12.3
boto31.34.124
botocore1.34.124

DyanamoDBの主要コンポーネントについて簡単に説明します(ドキュメント)。

コンポーネント説明
テーブル・データの集合
・例:下記のPeopleテーブル
項目・テーブル内のレコード
・項目は1以上の属性で構成される
・テーブルの各項目は一意の識別子(プライマリーキー)を持つ
・例:Peopleテーブルの場合、各項目は人を表す。プライマリーキーはPersonID。
属性・基盤となるデータ要素。属性は、それ以上分割できない。
・例:Peopleテーブルの場合、属性はPersonID、LastName、FirstNameなど。
出典:https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/HowItWorks.CoreComponents.html

プライマリーキー

DynamoDBには以下の2種類のプライマリーキーがある。

  1. パーティションキー
    • 1つの属性で構成されるシンプルなプライマリーキー。
    • 例:上記のPersonテーブルのPersonID
  2. パーティションキーとソートキー
    • 2つの属性で構成されるプライマリーキー。複合プライマリーキーとも呼ばれる。
    • 2つの属性のうち最初の属性はパーティションキー。2番目の属性はソートキー。
    • 複合プライマリーキーはクエリを実行するときの柔軟性を高める。パーティションキーのみ指定し、同一パーティションキーの全項目を取得するなど。

Boto3で使用する認証情報の設定方法については以下があります(参考)。

  1. boto.client() メソッドにパラメーターで渡された資格情報
  2. Session オブジェクトの生成時にパラメーターで渡された資格情報
  3. 環境変数
  4. 共有された認証情報ファイル(~/.aws/credentials)
  5. AWS設定ファイル(~/.aws/config)
  6. ロールの引き受けの提供
  7. Boto2設定ファイル(/etc/boto.cfg and ~/.boto)
  8. IAMロールを構成されたAmazon EC2インスタンス上ではそのインスタンスメタデータサービス

本記事のサンプルコードでは認証情報を環境変数で設定します。

import os

os.environ["AWS_ACCESS_KEY_ID"] = "xxxx"
os.environ["AWS_SECRET_ACCESS_KEY"] = "xxxx"
os.environ["AWS_SESSION_TOKEN"] = "xxxx"

Boto3にはクライアントインターフェイスとリソースインターフェイスがあります(ドキュメント)。

  • クライアントインターフェイス
    • 低レベルのインターフェイス。サービスAPIに1対1で対応し、DynamoDB が提供するすべてのAPIを利用できる。一方で、多くの場合、より冗長で使い方が複雑。
  • リソースインターフェイス
    • 上位レベルのインターフェイス。サービスAPIと1対1で対応するわけではない。つまり、リソースインターフェイスで使用できないAPIもある。一方で、batch_writerなどのサービスへのアクセスが便利。

リソースインターフェイスの改修は今後凍結されるようです(参考)。

本記事では、クライアントインターフェイスを使用します。

import boto3

client = boto3.client('dynamodb', region_name='ap-northeast-1')

以下のサンプルコードは、こちらのドキュメントを参考にしています。

テーブルの作成

response = client.create_table(
    TableName='People',
    KeySchema=[
        {
            'AttributeName': 'PersonID',
            'KeyType': 'HASH'  # プライマリーキー
        },
    ],
    AttributeDefinitions=[
        {
            'AttributeName': 'PersonID',
            'AttributeType': 'N'  # 数値
        },
    ],
    ProvisionedThroughput={
        "ReadCapacityUnits": 10,  # 1秒間に最大10回の4KBまでのデータ読み取りをサポート
        "WriteCapacityUnits": 10,  # 1秒間に最大5回の1KBまでのデータ書き込みをサポート
    },
)

項目の追加

response = client.put_item(
    Item={
        'PersonID': {
            'N': '101',
        },
        'LastName': {
            'S': 'Suzuki',
        },
        'FirstName': {
            'S': 'Taro',
        },
        'Age': {
            'N': '28',
        },
        'Phone': {
            'S': '090-1234-5678',
        },
        'Address': {
            'M': {
                'Street': {'S': '1-2-3 Jingumae'},
                'City': {'S': 'Shibuya-ku, Tokyo'},
                'Zip Code': {'S': '150-0001'},
                'Country': {'S': 'Japan'},
            }
        },
    },
    ReturnConsumedCapacity='TOTAL',  # 消費された書き込み容量単位の総数を返す。
    TableName='People',
)

複数の項目をまとめて追加する場合

response = client.batch_write_item(
    RequestItems={
        'People': [
            {
                'PutRequest': {
                    'Item': {
                        'PersonID': {
                            'N': '102',
                        },
                        'LastName': {
                            'S': 'Tanaka',
                        },
                        'FirstName': {
                            'S': 'Takuro',
                        },
                        'Phone': {
                            'S': '090-1111-1111',
                        },
                    },
                },
            },
            {
                'PutRequest': {
                    'Item': {
                        'PersonID': {
                            'N': '103',
                        },
                        'LastName': {
                            'S': 'Yamada',
                        },
                        'FirstName': {
                            'S': 'Jiro',
                        },
                        'Phone': {
                            'S': '090-2222-2222',
                        },
                    },
                },
            },
        ],
    },
)

print(response)

項目の取得

1つの項目を追加する場合

response = client.get_item(
    Key={
        'PersonID': {
            'N': '101',
        },
    },
    TableName='People',
)

print(response)

Query

以下の例では、Peopleテーブルの項目を取得します。 このテーブルにはパーティション・キー(PersonID)がありますが、このクエリはパーティション・キーを指定します。 以下のクエリーは、”102″の人を返します。

response = client.query(
    # KeyConditionExpressionで置換される値を定義
    ExpressionAttributeValues={
        ':v1': {
            'N': '102',
        },
    },
    # PersonIDがExpressionAttributeValuesで定義したv1に等しい項目を取得
    KeyConditionExpression='PersonID = :v1',
    TableName='People',
)

print(response)

Scan

以下の例では、Peopleテーブル全体をスキャンし、その結果をPersonID “102”の人に絞り込んでいます。各項目について、LastNameとFirstNameだけが返されます。

response = client.scan(
    ExpressionAttributeNames={
        '#LN': 'LastName',
        '#FN': 'FirstName',
    },
    ExpressionAttributeValues={
        ':p': {
            'N': '102',
        },
    },
    FilterExpression='PersonID = :p',
    ProjectionExpression='#LN, #FN',
    TableName='People',
)

print(response)

項目の削除

1つの項目を削除する場合

response = client.delete_item(
    Key={
        'PersonID': {
            'N': '101',
        },
    },
    TableName='People',
)

print(response)

複数の項目をまとめて削除する場合

response = client.batch_write_item(
    RequestItems={
        'People': [
            {
                'DeleteRequest': {
                    'Key': {
                        'PersonID': {
                            'N': '102',
                        },
                    },
                },
            },
            {
                'DeleteRequest': {
                    'Key': {
                        'PersonID': {
                            'N': '103',
                        },
                    },
                },
            },
        ],
    },
)

print(response)

テーブルの削除

response = client.delete_table(
    TableName='People'
)

参考

プロフィール
この記事を書いた人

30代半ばで未経験でプログラマーに転職し、日々奮闘中です
プログラミング、AI、NLP、キャリア関連などで少しでも役に立てる情報を発信していきます

ユウをフォローする
AWSPython
ユウをフォローする

コメント

タイトルとURLをコピーしました