概要
毎回boto3でDynamoDBを操作する場合の書き方を忘れるので、自分用のチートシートを作成します。
想定するテーブル
本ページで扱うテーブル情報は以下とします。
学校の科目ごとの成績を管理するテーブルです。
項目 | 内容 | 備考 |
---|---|---|
テーブル名 | school_score_table | |
パーティションキー(PK) | student | 生徒ごとにユニークな名称 |
ソートキー(SK) | subject | 科目はMath, English, Scienceなど |
グローバル セカンダリ インデックス(GSI) | subject-Index | 科目だけでクエリするためのインデックス |
入れておくレコードはこんな想定です。
[
{
'student': 'Alice',
'subject': 'Math',
'grade': 'A'
},
{
'student': 'Alice',
'subject': 'English',
'grade': 'B'
},
{
'student': 'Bob',
'subject': 'Math',
'grade': 'C'
},
{
'student': 'Bob',
'subject': 'English',
'grade': 'A'
}
]
DynamoDBのテーブル設定
最初のテーブル設定部分です。
URL
はパラメータストアやLambda環境変数から取ってくるのが良いです。
また、DynamoDBのテーブル操作が頻繁に行われるのであれば、テーブル名を変数や引数としたクラス化や関数化してあげるとスマートな気がします。
import boto3
from boto3.dynamodb.conditions import Key
URL = 'http://dynamodb.ap-northeast-1.amazonaws.com/xxxxxxxxxxxx/'
TABLE_NAME = 'school_score_table'
dynamodb = boto3.resource('dynamodb', endpoint_url=URL)
table = dynamodb.Table(TABLE_NAME)
テーブル操作
get_item
get_item()
は、テーブルから1つのレコードを取得します。
1つのレコードのため、応答は辞書型となります。
get_item()
はレコードが一意に決まるKey
を設定します。
今回はPKとSKでレコードが一意に決まるため、PKとSKを指定しています。
SKがない場合(PKだけで一意)の場合には、SKを指定する必要はありません。
response = table.get_item(
Key={
'student': 'Alice',
'subject': 'English'
}
)
print(response['Item'])
# {'student': 'Alice', 'subject': 'English', 'grade': 'B'}
query_item
query()
は、テーブルから条件に一致するレコードをKeyConditionExpression
で指定してリストで取得します。
クエリの仕方はいくつかバリエーションがあります。
PKだけでクエリする
response = table.query(
KeyConditionExpression=Key('student').eq('Alice')
)
print(response['Items'])
# [{'student': 'Alice', 'subject': 'Math', 'grade': 'A'}, {'student': 'Alice', 'subject': 'English', 'grade': 'B'}]
GSIでクエリする
response = table.query(
IndexName='subject-Index',
KeyConditionExpression=Key('subject').eq('Math')
)
print(response['Items'])
# [{'student': 'Alice', 'subject': 'Math', 'grade': 'A'}, {'student': 'Bob', 'subject': 'Math', 'grade': 'C'}]
query()
では、FilterExpression
を使ってクエリ結果の絞り込みができます。ただし、FilterExpression
の有無にかかわらず、使用されるRead Capacity Unit(読取容量)は変化しません。
put_item
put_item()
は、テーブルに1つのレコードを追加します。
既に同じ主キーを持つレコードがある場合は、古いアイテムを書き換えます。
table.put_item(
Item={
'student': 'Charly',
'subject': 'Math',
'grade': 'B'
}
)
新しい項目が既存の項目を置き換えるのを防ぐには、attribute_not_exists
関数と、PKの属性名を含む条件式を使用します。
以下はstudent
がない場合のみ、レコードを追加する処理の例です。
table.put_item(
Item=item,
ConditionExpression='attribute_not_exists(student)'
)
update_item
update_item()
は、指定したレコードを更新します。
指定したキーがない場合は、レコードを新たに追加します。
table.update_item(
Key={
'student': 'Alice',
'subject': 'Math'
},
UpdateExpression='SET grade = A+', # string型のプロパティはUpdateExpressionのみでOK
)
String型以外のプロパティの更新方法
UpdateExpression
は、string型のみ使用できます。
number型のプロパティを更新したい場合は、ExpressionAttributeValues
を使います。
table.update_item(
Key={
'student': 'Alice',
'subject': 'Math'
},
UpdateExpression='SET score = :val', # :valという変数を定義
ExpressionAttributeValues={
':val': 90 # 変数に入れる値を設定する
}
)
また、ExpressionAttributeNames
を指定することで、UpdateExpression
のプロパティ名を変数として定義できます。
table.update_item(
Key={
'student': 'Alice',
'subject': 'Math'
},
UpdateExpression='SET #key_name1 = :val1, #key_name2 = :val2',
ExpressionAttributeNames={
'#key_name1': 'score',
'#key_name2': 'grade',
},
ExpressionAttributeValues={
':val1': '90',
':val2': 'A+'
}
)
更新する条件を指定する
ConditionExpression
を使うと、更新する条件を指定できます。
以下はscore
の現在値が更新値よりも大きい場合のみ更新します。
table.update_item(
Key={
'student': 'Alice',
'subject': 'Math'
},
ConditionExpression='#key_name1 > :val1',
UpdateExpression='SET #key_name1 = :val1, #key_name2 = :val2',
ExpressionAttributeNames={
'#key_name1': 'score',
'#key_name2': 'grade',
},
ExpressionAttributeValues={
':val1': '90',
':val2': 'A+'
}
)
また、ConditionExpression
を満たさない場合、ConditionalCheckFailedException
により書込みが失敗します。
delete_item
delete_item()
は、テーブルのレコードを1つ削除します。
指定の仕方はget_item()
と同じようにKey
を使います。
table.delete_table(
Key={
'student': 'Alice',
'subject': 'English'
}
)
まとめ
自分の習熟度に応じて、随時更新していきたいと思います。