AWS CLI での DynamoDB 条件付き書き込み

条件付き書き込みはシェルから送るのは簡単ですが、読む のは厄介です。失敗したときの面白い結果が、出力ではなくエラーとして届くからです。DynamoDB の条件式は式で何を表現できるかを扱います。このページは、それを CLI から実行し、負けたアイテムを失敗の中から取り出す方法についてです。

コード

aws dynamodb update-item \
  --table-name 'Music' \
  --key '{"Artist":{"S":"Arturo Sandoval"},"SongTitle":{"S":"Cubano Chant"}}' \
  --update-expression 'SET #upd0 = :updValue0, #version = :newVersion' \
  --condition-expression 'attribute_exists(#cond0) AND #version = :expectedVersion' \
  --expression-attribute-names '{"#upd0":"Genre","#version":"Version","#cond0":"Artist"}' \
  --expression-attribute-values '{":updValue0":{"S":"Latin Jazz"},":expectedVersion":{"N":"7"},":newVersion":{"N":"8"}}'

成功するとコマンドは何も出力せず、終了コード 0 で終わります。別の書き込み手が先に到達していれば条件は失敗し、CLI はサービスのメッセージを報告します。

An error occurred (ConditionalCheckFailedException) when calling the UpdateItem operation:
The conditional request failed

解説

  • 成功は無言。出力なし、終了コード 0。パースするものも表明するものもないので、シェルスクリプトは終了ステータスを結果として扱うしかありません。更新後のアイテムを表示したいなら --return-values ALL_NEW を足します。
  • 失敗は終了ステータス 254 で、これは CLI v2 におけるクライアント側エラーのコードであり、不正なリクエストと共有されています。リトライする前にメッセージで分岐しましょう。さもないと式のタイプミスが無限のバックオフループになります。
  • --return-values-on-condition-check-failure ALL_OLD はここで実際に効きます。有効な値は ALL_OLDNONE で、読み取りキャパシティは消費しません。エラーからアイテムを取り出すにはもう 1 つフラグが要ります。下で扱います。
  • 条件と更新は別々のフラグですが、名前空間は共有します--expression-attribute-names--expression-attribute-values--update-expression--condition-expression にまたがってマージされます。だからこそ生成される名前は句ごとに振り直されず #upd0#cond0 と続くのです。1 つのプレースホルダーを 2 つの異なる意味で使い回すと、後勝ちで静かに上書きされます。
  • 失敗した書き込みにも課金されます。デベロッパーガイドは明確です。条件が false と評価されてもやはり書き込みキャパシティを消費し、その大きさは古いアイテムと新しいアイテムの大きい方で決まります。条件は安価な存在チェックではありません。

失敗時の出力と、そこからアイテムを取り出す方法

このフェンスを 1 回実行すると、静かに成功します。Version がもう 7 ではなくなった状態で 2 回目を実行すると、aws-cli/2.36.9 は標準エラー出力にこう表示します。

aws: [ERROR]: An error occurred (ConditionalCheckFailedException) when calling the UpdateItem operation: The conditional request failed

--return-values-on-condition-check-failure ALL_OLD を足すと、デフォルトの出力は「まだ続きがある」ことだけを、中身を見せずに伝えます。

aws: [ERROR]: An error occurred (ConditionalCheckFailedException) when calling the UpdateItem operation: The conditional request failed

Additional error details:
Item: <complex value>
Use "--cli-error-format json" or another error format to see the full details.

<complex value> がそのアイテムで、デフォルトのテキストレンダラーが伏せています。--cli-error-format json を足すと、全部が表示されます。

{
    "Message": "The conditional request failed",
    "Code": "ConditionalCheckFailedException",
    "Item": {
        "Artist": {"S": "Arturo Sandoval"},
        "Year": {"N": "1994"},
        "Version": {"N": "8"},
        "SongTitle": {"S": "Cubano Chant"},
        "AlbumTitle": {"S": "Danzon"},
        "Genre": {"S": "Latin Jazz"}
    }
}

(属性マップは 1 つずつ 1 行に畳んでいます。それ以外は出力されたままです。)1 回目の実行が成功したので Version は 8 になり Genre も設定されています。これが、シェルスクリプトから閉じた楽観的ロックのループです。標準エラー出力を jq -r '.Item.Version.N' に通し、その値を :expectedVersion として戻し、リトライする。get-item は不要で、読み取りとリトライの間に第三の書き込み手が滑り込む隙間もありません。

リトライはただではありません。拒否された試行ごとに書き込みユニットを 1 つ消費するので、競合するキーをタイトループで叩くと、進捗ゼロのまま着実に課金されます。料金計算ツールは、試行回数に上限を設ける前に、リトライの嵐が実際いくらかかるのかを知りたいときに、書き込みレートを月額の数字に変えてくれます。

プレースホルダーのマップをシェルでクォートすることなく、自分のテーブルに対してこうしたガードを実行するには、DynoTable をダウンロードしてください。

関連する例

参考資料

最終検証日 2026-07-28、上記にリンクした公式 AWS ドキュメントに照らして確認しました。

Console なしで DynamoDB を扱う

DynamoDB では実行できない本物の SQL(JOINs、GROUP BY、集計)を実行する高速な DynamoDB デスクトップクライアント。ビジュアル編集と、あなた自身の Bedrock キーで動く AI エージェントを備えています。

30日間無料トライアル、クレジットカード不要 — その後は期限のない Free プラン。