DynamoDBテーブルのアイテムを追加したり更新するとき、条件として下記をよく利用します。
- attribute_not_exists()
- attribute_exists()
ふと思いました。「たとえば、dict(map)の深い階層のAttributeに対しても使えるのだろうか?」と。試してみました。
おすすめの方
- DynamoDBの条件指定について知りたい方
- DynamoDBの条件式の組み込み関数について知りたい方
適当なDynamoDBテーブルを用意する
既存の適当なDynamoDBテーブルを利用します。
まずは、最上位のAttributeで試す
app1.py
import boto3
dynamodb = boto3.resource("dynamodb")
table = dynamodb.Table("boto3-test")
def main():
print("--- init ---")
table.put_item(
Item={"todoId": "t0001", "title": "あめちゃんを買う", "deadline": "2023-09-15"}
)
# title が無いなら、追加したい
print("--- expected: ConditionalCheckFailedException ---")
try:
table.update_item(
Key={"todoId": "t0001"},
UpdateExpression="set #title = :title",
ExpressionAttributeNames={"#title": "title"},
ExpressionAttributeValues={":title": "アイスを買う"},
ConditionExpression="attribute_not_exists(title)",
)
except Exception as e:
print(e)
# note があるなら、更新したい
print("--- expected: ConditionalCheckFailedException ---")
try:
table.update_item(
Key={"todoId": "t0001"},
UpdateExpression="set #note = :note",
ExpressionAttributeNames={"#note": "note"},
ExpressionAttributeValues={":note": "予算は300円"},
ConditionExpression="attribute_exists(note)",
)
except Exception as e:
print(e)
if __name__ == "__main__":
main()
これは、期待通りの動作でした。
--- init ---
--- expected: ConditionalCheckFailedException ---
An error occurred (ConditionalCheckFailedException) when calling the UpdateItem operation: The conditional request failed
--- expected: ConditionalCheckFailedException ---
An error occurred (ConditionalCheckFailedException) when calling the UpdateItem operation: The conditional request failed
深い階層にあるAttributeで試す
次の2つに対して、attribute_not_exists()
とattribute_exists()
を試してみます。
- detail.color.blue
- detail.color.white
app.py
import boto3
dynamodb = boto3.resource("dynamodb")
table = dynamodb.Table("boto3-test")
def main():
print("--- init ---")
table.put_item(
Item={
"todoId": "t0001",
"detail": {
"title": "あめちゃんを買う",
"color": {"red": "#ff0000", "green": "#00ff00", "blue": "#0000ff"},
"deadline": "2023-09-15",
},
}
)
# blue が無いなら、 bule をこっそり追加する
print("--- expected: ConditionalCheckFailedException ---")
try:
table.update_item(
Key={"todoId": "t0001"},
UpdateExpression="set #detail.#color.#blue = :black",
ExpressionAttributeNames={
"#detail": "detail",
"#color": "color",
"#blue": "blue",
},
ExpressionAttributeValues={":black": "#000000"},
ConditionExpression="attribute_not_exists(#detail.#color.#blue)",
)
except Exception as e:
print(e)
# white が有るなら、 white をこっそり変える
print("--- expected: ConditionalCheckFailedException ---")
try:
table.update_item(
Key={"todoId": "t0001"},
UpdateExpression="set #detail.#color.#white = :black",
ExpressionAttributeNames={
"#detail": "detail",
"#color": "color",
"#white": "white",
},
ExpressionAttributeValues={":black": "#000000"},
ConditionExpression="attribute_exists(#detail.#color.#white)",
)
except Exception as e:
print(e)
if __name__ == "__main__":
main()
「ConditionalCheckFailedException」が発生しました。
--- init ---
--- expected: ConditionalCheckFailedException ---
An error occurred (ConditionalCheckFailedException) when calling the UpdateItem operation: The conditional request failed
--- expected: ConditionalCheckFailedException ---
An error occurred (ConditionalCheckFailedException) when calling the UpdateItem operation: The conditional request failed
さいごに
深い階層でも問題なく利用できました。これは嬉しいですね。 複雑なデータの深いAttributeを条件付きで更新したい場合などでもバッチリです。 参考になれば幸いです。