この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは、CX事業本部 IoT事業部の若槻です。
Amazon DynamoDBではアイテム更新(UpdateItem
)時にAttributeの上書きを防止するための機能があります。
If you want to avoid overwriting an existing attribute, you can use
SET
with theif_not_exists
function. (The function name is case sensitive.) Theif_not_exists
function is specific to theSET
action and can only be used in an update expression. The syntax is as follows.-
if_not_exists (path, value)
If the item does not contain an attribute at the specified
path
,if_not_exists
evaluates to value; otherwise, it evaluates topath
.
第一引数に指定したパスのAttributeがアイテムに未設定であれば、第二引数に指定した値で置き換えるというものです。
今回は、このif_not_exists
構文を利用するパターンをいくつか試して、使いどころを確認してみました。
環境準備
sampleTable
テーブル作成。
aws dynamodb create-table \
--table-name sampleTable \
--attribute-definitions AttributeName=id,AttributeType=S \
--key-schema AttributeName=id,KeyType=HASH \
--billing-mode PAY_PER_REQUEST
アイテム作成。
aws dynamodb put-item --table-name sampleTable --item '{"id":{"S":"s001"}}'
aws dynamodb put-item --table-name sampleTable --item '{"id":{"S":"s002"}}'
aws dynamodb put-item --table-name sampleTable --item '{"id":{"S":"s003"}}'
if_not_exists構文を使う
値の設定
SET path = if_not_exists (path, value)
というUpdateExpressionの場合。
Attribute(username
)が未設定の場合、指定した値(mesoko
)が設定されました。
$ aws dynamodb update-item \
--table-name sampleTable \
--key '{"id":{"S":"s001"}}' \
--update-expression "SET username = if_not_exists(username, :n)" \
--expression-attribute-values '{":n": {"S": "mesoko"}}' \
--return-values ALL_NEW
{
"Attributes": {
"id": {
"S": "s001"
},
"username": {
"S": "mesoko"
}
}
}
Attribute(username
)が設定済みの場合も、指定した値(mesoko2
)が設定されませんでした。
$ aws dynamodb update-item \
--table-name sampleTable \
--key '{"id":{"S":"s001"}}' \
--update-expression "SET username = if_not_exists(username, :n)" \
--expression-attribute-values '{":n": {"S": "mesoko2"}}' \
--return-values ALL_NEW
{
"Attributes": {
"id": {
"S": "s001"
},
"username": {
"S": "mesoko"
}
}
}
Attributeが未設定の場合のみ更新されるという、上書き防止の動作を確認することができました。
ちなみにSET path = value
とすれば、Attributeが設定済みであるか未設定であるかに関わらず、指定の値を設定できました。
aws dynamodb update-item \
--table-name sampleTable \
--key '{"id":{"S":"s001"}}' \
--update-expression "SET username2 = :n" \
--expression-attribute-values '{":n": {"S": "mesoko2"}}' \
--return-values ALL_NEW
{
"Attributes": {
"username": {
"S": "mesoko"
},
"username2": {
"S": "mesoko2"
},
"id": {
"S": "s001"
}
}
}
数値加算
SET path = if_not_exists (path, value) + value2
という数値加算を行うUpdateExpressionの場合。
Attribute(price
)が未設定の場合、if_not_exists
の第二引数(:i
) + 加算数(:p
)の値で更新されました。
$ aws dynamodb update-item \
--table-name sampleTable \
--key '{"id":{"S":"s002"}}' \
--update-expression "SET price = if_not_exists(price, :i) + :p" \
--expression-attribute-values '{":p": {"N": "100"}, ":i": {"N": "10"}}' \
--return-values ALL_NEW
{
"Attributes": {
"id": {
"S": "s002"
},
"price": {
"N": "110"
}
}
}
Attribute(price
)が設定済みの場合、if_not_exists
の第一引数(price
) + 加算数(:p
)の値で更新されました。
$ aws dynamodb update-item \
--table-name sampleTable \
--key '{"id":{"S":"s002"}}' \
--update-expression "SET price = if_not_exists(price, :i) + :p" \
--expression-attribute-values '{":p": {"N": "100"}, ":i": {"N": "10"}}' \
--return-values ALL_NEW
{
"Attributes": {
"id": {
"S": "s002"
},
"price": {
"N": "210"
}
}
}
数値加算では、Attributeが未設定の場合に、加算される数に既定値が使用される動作を確認できました。
リストへの要素追加
SET path = list_append(if_not_exists (path, value), value2)
というリストへの要素追加を行うUpdateExpressionの場合。
Attribute(office_list
)が未設定の場合、if_not_exists
の第二引数(:init_list
)に要素(:e
)が追加されました。
$ aws dynamodb update-item \
--table-name sampleTable \
--key '{"id":{"S":"s003"}}' \
--update-expression "SET office_list = list_append(if_not_exists(office_list, :init_list), :e)" \
--expression-attribute-values '{":init_list": {"L": [{"S": "sakuma"}]}, ":e": {"L": [{"S": "iwamoto-cho"}]}}' \
--return-values ALL_NEW
{
"Attributes": {
"id": {
"S": "s003"
},
"office_list": {
"L": [
{
"S": "sakuma"
},
{
"S": "iwamoto-cho"
}
]
}
}
}
Attribute(office_list
)が設定済みの場合、if_not_exists
の第一引数(office_list
)に要素(:e
)が追加されました。
$ aws dynamodb update-item \
--table-name sampleTable \
--key '{"id":{"S":"s003"}}' \
--update-expression "SET office_list = list_append(if_not_exists(office_list, :init_list), :e)" \
--expression-attribute-values '{":init_list": {"L": [{"S": "sakuma"}]}, ":e": {"L": [{"S": "hibiya"}]}}' \
--return-values ALL_NEW
{
"Attributes": {
"id": {
"S": "s003"
},
"office_list": {
"L": [
{
"S": "sakuma"
},
{
"S": "iwamoto-cho"
},
{
"S": "hibiya"
}
]
}
}
}
リストへの要素追加では、Attributeが未設定の場合に、追加されるリストに既定値が使用される動作を確認できました。
後始末
テーブル削除。
aws dynamodb delete-table --table-name sampleTable
おわりに
Amazon DynamoDBのUpdateItemでのif_not_exists構文の使いどころを確認してみました。
Attributeが未設定の場合を考慮する必要がある場合に役に立ちそうです。
参考
- create-table — AWS CLI 2.9.6 Command Reference
- put-item — AWS CLI 2.9.6 Command Reference
- DynamoDBでデータを更新する際に使うUpdateExpressionについて一通りまとめてみた | DevelopersIO
- amazon dynamodb - Is it possible to combine if_not_exists and list_append in update_item - Stack Overflow
以上