DynamoDBのReturnValues:書き込みから古いまたは新しいアイテムを取得する
デフォルトでは、DynamoDBの書き込みは成功以外に何も返しません。しかし、書き込みの
周辺のデータ — 変更前の値や、変更後の新しい値 — が必要になることはよくあります。
素朴な解決策は2回目のGetItemですが、これは余分な往復であり、競合でもあります:
その間に別の誰かが書き込めるのです。DynamoDBは**ReturnValues**パラメータで両方を
回避します。これは書き込み自体の一部として、古いまたは新しいアイテムをアトミックに
返します。
DynamoDBのReturnValuesは何をするのか?
ReturnValuesは、DynamoDBの書き込みに対して同じ呼び出しの中でアイテムを返すよう指示します。これにより、2回目のGetItemとそれが生む競合状態を回避できます。PutItemとDeleteItemはNONEまたはALL_OLDのみを受け付け、UpdateItemは5つすべて(NONE、ALL_OLD、UPDATED_OLD、ALL_NEW、UPDATED_NEW)を受け付け、古いまたは新しい値をアトミックに返します。
ReturnValuesは書き込みの一部としてアイテムを返す — 2回目の読み取りも、競合もなし。NONE(デフォルト) — 何も返さない。ALL_OLD— 書き込み前の状態のアイテム全体。UPDATED_OLD— 更新が変更した属性のみの、変更前の値。ALL_NEW— 書き込み後のアイテム全体。UPDATED_NEW— 変更された属性のみの、変更後の値。PutItem/DeleteItemはNONEまたはALL_OLDのみを受け付け、UpdateItemは5つ すべてを受け付ける。
問題:今上書きした値が必要
サポートデスクを運用していて、担当者がチケットのステータスをopenからpendingに
変更するとします。監査ログには、変更前のステータスが何だったかを記録する必要が
あります。ReturnValuesがなければ、こうするでしょう:
- 現在のステータスを読み取る
GetItem、 - 新しいものを設定する
UpdateItem。
ステップ1と2の間に別の担当者がステータスを変更するかもしれません — すると監査ログは
古い「変更前」の値を記録してしまいます。さらに悪いことに、1つの論理的な操作に対して
2回の呼び出しです。ReturnValuesはこれを、書き込み時点で実際にそうだった古いステータスを
返す、単一のアトミックなUpdateItemにまとめます。
5つの選択肢と、それぞれの使いどころ
UpdateItemはすべてをサポートします。選択は、アイテムのどの部分と書き込みのどちら側が
必要かです:
ReturnValues | 返すもの | 使う場面 |
|---|---|---|
NONE | なし | アイテムを返す必要がない(デフォルト) |
ALL_OLD | アイテム全体、書き込み前 | 監査 / 「今何を置き換えた?」 |
UPDATED_OLD | 変更した属性、書き込み前 | 触れたフィールドだけ気にする場合 |
ALL_NEW | アイテム全体、書き込み後 | 呼び出し元に返す新しい完全なアイテムが必要な場合 |
UPDATED_NEW | 変更した属性、書き込み後 | 今インクリメントしたカウンター/値を読み戻す場合 |
UPDATED_NEWは日常の主役です:更新式でカウンターを
インクリメントし、同じ呼び出しで新しい合計を読み戻します。競合はありません。サポート
チケットの監査では、ALL_OLD(ステータスフィールドだけをログに記録するなら
UPDATED_OLD)が変更前の状態をアトミックに捉えます。
非対称性に注目してください:PutItemとDeleteItemはNONEとALL_OLDのみをサポート
します — deleteには返すべき「新しい」値がなく、putの新しい値はまさに送ったものだから
です。その場で変更するUpdateItemだけが5つすべてを提供します。
AWSのドキュメント
に正確な対応表があります。
DynoTableでの更新の書き込み
DynamoDB式ビルダーでUpdateItemとその更新式を
ビジュアルに組み立てましょう — SET/ADD句に加えて属性名と値のマップを出力します。
アプリ内では、ステージした書き込みがコミットされた後にDynoTableが結果のアイテムを表示
するので、新しい状態を直接確認できます。

落とし穴と次のステップ
- 変更の周辺を読むために
GetItemしてから書き込んではいけない — 往復であり競合です。ReturnValuesを使いましょう。 UPDATED_*は触れた属性のみを返す — アイテム全体が必要ならALL_*を使いましょう。PutItem/DeleteItemは新しい値を返せない —NONE/ALL_OLDのみです。ReturnValuesは条件の代わりにはならない — 書き込みをガードするには 条件式を追加し、その効果を読み戻すにはReturnValuesを使いましょう。両者は組み合わせられます。- 関連: 更新式、 アトミックカウンター。
2回の呼び出しをスクリプトで書かずに編集を行い、変更前後を確認したいですか? DynoTableをダウンロードして、アイテムを直接編集してください。


