Node.js 中的 DynamoDB BatchWriteItem(AWS SDK v3)

BatchWriteItem 在一次請求中放入或刪除多達 25 個項目。它不是一個比較小的 UpdateItem:每個 PutRequest 都會替換掉整個項目,而 v3 的型別也沒有讓你附加條件的地方。DynamoDB 的批次操作談了那些限制與部分失敗的模型;本頁談的是 v3 的這個呼叫,以及它悄悄弄丟資料的那唯一一種方式。

程式碼

import {BatchWriteItemCommand, DynamoDBClient} from '@aws-sdk/client-dynamodb';

const client = new DynamoDBClient({region: 'us-east-1'});

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

let requestItems = {
  Music: [
    {
      PutRequest: {
        Item: {
          Artist: {S: 'Arturo Sandoval'},
          SongTitle: {S: 'Cubano Chant'},
          AlbumTitle: {S: 'Danzon'},
          Year: {N: '1994'}
        }
      }
    },
    {
      PutRequest: {
        Item: {
          Artist: {S: 'Arturo Sandoval'},
          SongTitle: {S: 'A Mis Abuelos'},
          AlbumTitle: {S: 'Danzon'},
          Year: {N: '1994'}
        }
      }
    },
    {
      DeleteRequest: {
        Key: {Artist: {S: 'Ella Fitzgerald'}, SongTitle: {S: 'Misty'}}
      }
    }
  ]
};

let attempt = 0;

do {
  const response = await client.send(new BatchWriteItemCommand({RequestItems: requestItems}));

  // Writes that were throttled come back in UnprocessedItems — resubmit them
  // with exponential backoff until the map is empty.
  requestItems = response.UnprocessedItems;
  if (requestItems && Object.keys(requestItems).length > 0) {
    attempt += 1;
    await sleep(Math.min(100 * 2 ** attempt, 5000));
  }
} while (requestItems && Object.keys(requestItems).length > 0);

console.log('Batch written');

說明

  • 剩下來的那個成員叫 UnprocessedItems,不是 UnprocessedKeys。讀取端用的是另一個名字,而在 JavaScript 裡這種拼字錯誤照樣能編譯、讀出來是 undefined,然後把 do/while 變成一次就結束的呼叫,把被節流的寫入丟在地上。TypeScript 抓得到;純 JS 抓不到。
  • 沒有地方放條件。v3 的 WriteRequest 型別剛好只有兩個選用成員 PutRequestDeleteRequest,兩者都不接受 ConditionExpressionReturnValues。這不是 SDK 保守:API 參考說你無法在個別的 put 與 delete 請求上指定條件。如果一個寫入需要防護,它就不屬於批次,而屬於 帶條件的 UpdateItem 或一筆交易。
  • 兩個能被 catch 到的錯誤,兩者都不可重試,依 err.name 區分。二十六個項目會引發 ValidationException / Too many items requested for the BatchWriteItem call。碰同一個鍵兩次會引發 Provided list of item keys contains duplicates,而這個訊息連 put+delete 的組合也一併涵蓋,第一次看到時讀起來有點怪。
  • 整批被拒的清單比顯而易見的那三項更長。除了超過 25 個請求、單一項目超過 400 KB 與總計超過 16 MB 之外,DynamoDB 也會因為資料表不存在、鍵與結構不符、分割區索引鍵超過 2048 位元組,或排序索引鍵超過 1024 位元組而拒絕整批。一個壞項目就讓你賠掉全部 25 個。
  • 批次買到的是往返次數,不是容量。每個項目都會被當成獨立的 PutItemDeleteItem 計費、進位到 1 KB,而針對不存在項目的刪除仍會消耗一個寫入單位。

只帶鍵的 PutRequest 會摧毀項目的其餘部分

Ella Fitzgerald / Misty 一開始帶著 AlbumTitleYear。送出一個只帶那兩個鍵屬性的 PutRequest

{PutRequest: {Item: {Artist: {S: 'Ella Fitzgerald'}, SongTitle: {S: 'Misty'}}}}

接著用 ConsistentRead: true 把它讀回來。DynamoDB Local 3.3.0 回傳:

{
  "Artist": { "S": "Ella Fitzgerald" },
  "SongTitle": { "S": "Misty" }
}

AlbumTitleYear 不見了。呼叫成功了、UnprocessedItems{},而回應裡沒有任何東西提到它丟掉的那兩個屬性。put 是整個項目的替換,所以一個由局部酬載組成的批次(一個 API 請求主體、一個 CSV 欄位子集、一個省略了屬性的投影 Query 結果)會抹掉酬載沒帶到的每一個屬性。

當你把批次拿來做感覺像更新的事情時,這就是要預先設想的失效模式。修法是先讀取目前的項目再合併,或者乾脆不用批次,改用 UpdateItem — 它只會碰你點名的那些屬性。

一個 25 項目的批次會縮成 12 項目的另一個原因是大小。寫入計費時每筆都會進位到 1 KB,而請求上限是 16 MB,所以項目真正的位元組數同時決定了你的帳單與能塞進幾個。項目大小計算機會在你組出那個陣列之前,逐項目給你那個數字。

想大量載入、編輯與刪除項目,又不想親手處理替換語意,就下載 DynoTable

相關範例

參考資料

最後查證於 2026-07-28,對照上方連結的官方 AWS 文件。

不必透過主控台就能操作 DynamoDB

一款快速的 DynamoDB 桌面用戶端,可執行 DynamoDB 無法執行的真正 SQL — JOINs、GROUP BY、聚合 — 並支援視覺化編輯與使用你自己的 Bedrock 金鑰的 AI 代理。

30 天免費試用,無需信用卡 — 之後為無時間限制的免費方案。