DynamoDBテーブルの attribute_exists() が最上位のAttribute以外でも使えるか試してみる

ふかーーーいAttributeでも、利用できました。
2023.09.07

DynamoDBテーブルのアイテムを追加したり更新するとき、条件として下記をよく利用します。

  • attribute_not_exists()
  • attribute_exists()

ふと思いました。「たとえば、dict(map)の深い階層のAttributeに対しても使えるのだろうか?」と。試してみました。

おすすめの方

  • DynamoDBの条件指定について知りたい方
  • 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を条件付きで更新したい場合などでもバッチリです。 参考になれば幸いです。

参考