kazu22002の技術覚書

PHPer, Golang, AWS エンジニアの日々

DynamoDBを理解するための訓練 ~データ操作~

DynamoDBへのCRADをSDKを利用して試します。

言語はpythonにしました。(サンプルがpythonだったのと、機械学習を重点的に取り組んでいきたくなったので。)

dynamoDB localへのアクセス

boto3のインストール

boto3.amazonaws.com

pip install boto3
import boto3

dynamodb_resource = boto3.resource('dynamodb', endpoint_url='http://localhost:8000')

endpoint_urlを指定することで対象のdynamoDBへアクセスすることが可能になります。

create

テーブルを作成します。テーブル作成時にプライマリーkeyの内容を指定します。

primary keyにはhashとhash rangeがあるみたいです。

import boto3

dynamodb_resource = boto3.resource('dynamodb', endpoint_url='http://localhost:8000')

# Create the DynamoDB table.
table = dynamodb_resource.create_table(
    TableName='test',
    KeySchema=[
        {
            'AttributeName': 'id',
            'KeyType': 'HASH'
        },
    ],
    AttributeDefinitions=[
        {
            'AttributeName': 'id',
            'AttributeType': 'S'
        },
    ],
    ProvisionedThroughput={
        'ReadCapacityUnits': 5,
        'WriteCapacityUnits': 5
    }
)

table.meta.client.get_waiter('table_exists').wait(TableName='test')

print(table.item_count)

実行してテーブルができていれば、完了です。

put

適当にデータを追加してみます。

import boto3
import uuid

dynamodb_resource = boto3.resource('dynamodb', endpoint_url='http://localhost:8000')
sample_table = dynamodb_resource.Table('test')


def create_data(item):

    # jsonのデータ数分ループしDynamoDBにPut
    sample_table_put_item_response = sample_table.put_item(
        Item={
            'id': str(uuid.uuid4()),
            'target_date': item['date'],
            'count': item['value'],
        }
    )
    response = {
        "statusCode": 200
    }
    print(sample_table_put_item_response)
    return response


date_list = ["2020-01-01", "2020-01-02", "2020-01-03"]

for date in date_list:
    for i in range(10):
        item = {"value": i, "date": date}
        create_data(item)

idをuuidにして一意にするようにしています。

get

プライマリーキーを使用したデータ取得になります。

import boto3

dynamodb_resource = boto3.resource('dynamodb', endpoint_url='http://localhost:8000')
sample_table = dynamodb_resource.Table('test')


def get_data(key):
    items = sample_table.get_item(
        Key={
            "id": key
        }
    )
    return items


print(get_data("48602275-9d42-4cbf-ac14-75fcbfed90d9"))
print(get_data("1bacac4c-da25-4ea6-a290-fb2bbc187b21"))
print(get_data("e9c228e2-71bd-43eb-8b02-874d1c00a549"))

get_dataには登録した内容からidの値を指定しています。

query

indexを作成している必要がありそうなため、exampleから引用しました。

response = table.query(
    KeyConditionExpression=Key('username').eq('johndoe')
)
items = response['Items']
print(items)

基本はqueryを使うみたいですね。index周りの理解があまいためしっかりと動作させていません。

データ取得を理解するといろいろとアプリに使用できそうです。

scan

queryとscanの違いについてはamazonが説明しており、基本的にはscanを使用しないほうが良いと言っています。

一般に、Scan オペレーションよりも、DynamoDB の他のオペレーションのほうが効率的です。Scan オペレーションでは、常にテーブル全体、または セカンダリインデックス をスキャンします。その後、目的の結果を得るために値にフィルタを適用します。基本的には、結果セットからデータを削除するステップが追加されます。

docs.aws.amazon.com

import boto3
from boto3.dynamodb.conditions import Key, Attr

dynamodb_resource = boto3.resource('dynamodb', endpoint_url='http://localhost:8000')
sample_table = dynamodb_resource.Table('test')

res = sample_table.scan(
    FilterExpression=Attr('date').eq("2020-01-01")
)
for row in res['Items']:
    print(row)

res = sample_table.scan(
    FilterExpression=Attr('value').eq(1)
)
for row in res['Items']:
    print(row)

update

import boto3

dynamodb_resource = boto3.resource('dynamodb', endpoint_url='http://localhost:8000')
sample_table = dynamodb_resource.Table('test')

sample_table.update_item(
    Key={
        'id': '25fa2cd2-826b-4c9e-979a-021c8ec88034',
    },
    UpdateExpression='SET target_date = :val1',
    ExpressionAttributeValues={
        ':val1': "2001-01-01"
    }
)

delete

import boto3

dynamodb_resource = boto3.resource('dynamodb', endpoint_url='http://localhost:8000')
sample_table = dynamodb_resource.Table('test')

sample_table.delete_item(
    Key={
        'id': '48602275-9d42-4cbf-ac14-75fcbfed90d9',
    }
)

予約語がわからない

keyの値をdate, valueにしていたらupdateでエラーがでました。

botocore.exceptions.ClientError: An error occurred (ValidationException) when calling the UpdateItem operation: Invalid UpdateExpression: Attribute name is a reserved keyword; reserved keyword: date

「属性名は予約済みのキーワードです。」

データを作ることは可能なので、注意が必要そうです。

雑記

一度更新を忘れると、書かなくなりますね。何度反省すればいいんだろう。