Node.js 中的 DynamoDB BatchGetItem(AWS SDK v3)
BatchGetItem 在一次請求中依主索引鍵取回多達 100 個項目。在 AWS SDK v3 中,這個呼叫必須寫成迴圈,因為 UnprocessedKeys 是隨著一次_成功_的回應回來,而不是隨著錯誤回來。是什麼把它填滿,以及為什麼 16 MB 與每個分割區 1 MB 才是要緊的數字,DynamoDB 的批次操作裡談過。本頁談的是 v3 的這個呼叫,以及它交還給你的東西。
程式碼
import {BatchGetItemCommand, 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: {
Keys: [
{Artist: {S: 'Arturo Sandoval'}, SongTitle: {S: 'Cubano Chant'}},
{Artist: {S: 'Arturo Sandoval'}, SongTitle: {S: 'A Mis Abuelos'}},
{Artist: {S: 'Ella Fitzgerald'}, SongTitle: {S: 'Misty'}}
]
}
};
const items = [];
let attempt = 0;
do {
const response = await client.send(new BatchGetItemCommand({RequestItems: requestItems}));
items.push(...(response.Responses?.Music ?? []));
// A partial result is NOT an error: throttling, a >16 MB response, or an
// internal failure returns the leftovers in UnprocessedKeys. Retry them
// with exponential backoff.
requestItems = response.UnprocessedKeys;
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(`Fetched ${items.length} items`);說明
- 那些選用鏈結不是防禦性的雜訊。
Responses與UnprocessedKeys在 v3 的型別中都是選用的,所以response.Responses?.Music ?? []與那個Object.keys()防護正是編譯器要求的東西。在純 JavaScript 中,它們是攔住第一個空回應拋出例外的東西。 - 依
err.name分支。v3 把服務端錯誤代碼放在那裡,而這個命令真正會拋出的兩種失敗都不可重試,所以它們絕不能掉進退避迴圈裡。超過 100 個鍵會得到ValidationException/Too many items requested for the BatchGetItem call;同一個鍵給兩次會得到Provided list of item keys contains duplicates。兩者都在 Python 頁面上逐字重現過。 UnprocessedKeys回來時就已經是RequestItems的形狀,這也是迴圈能直接把它指派回去的唯一原因。它不是分頁游標,也不代表呼叫失敗了。- 退避是 AWS 的指示,不是錦上添花。API 參考告訴你要用 "an exponential backoff algorithm",因為立刻重試會落到同一個被節流的分割區上。
ConsistentRead與ProjectionExpression是逐一資料表設定的,寫在每個RequestItems項目內部,而不是最上層。當這個對應只有一個鍵、看起來像個扁平請求時,這一點很容易漏掉。
回應實際回傳的樣子
針對三首歌都在的 DynamoDB Local 3.3.0 執行上面那段程式碼,加上 ReturnConsumedCapacity: 'TOTAL',並印出歌名而不是數量:
order: [ 'A Mis Abuelos', 'Misty', 'Cubano Chant' ]
UnprocessedKeys: {}
ConsumedCapacity: [ { TableName: 'Music', CapacityUnits: 1.5 } ]請求列出的順序是 Cubano Chant、A Mis Abuelos、Misty。回應一個位置都沒對上,這正是迴圈要往一個扁平陣列裡 push、而不是依索引位置取值的原因。用鍵屬性把項目和請求對回去,並把那些鍵包含進任何 ProjectionExpression 裡,好讓你還有東西可以對。
在同一個 Music 項目上設定 ConsistentRead: true,同樣這三個鍵就要花 3 個單位而不是 1.5 個。三個各自小於 4 KB 的項目會被當成三次獨立的 GetItem 讀取來計費,最終一致性讀取每次半個單位,強一致性讀取每次一個單位。定價計算機會在你敲定讀取模式之前,把這種逐項目的算術換算成一個月度數字。
現在刪掉 Misty 再跑一次:兩個項目、一個空的 UnprocessedKeys,以及 1.0 個單位。那個缺席的鍵一毛錢都沒算。這是 DynamoDB Local 的產物,不是契約;BatchGetItem 參考(2026-07-28 取回)寫明,對不存在項目的請求仍會依該讀取類型消耗最低讀取容量。別拿本機執行的結果,來替一批快取未命中做容量估算。
想把一組鍵讀回來、看看到底回傳了什麼,又不想先寫這個迴圈,就下載 DynoTable。
相關範例
- Python 中的 DynamoDB BatchGetItem — 以 boto3 做同一件批次讀取。
- 以 AWS CLI 執行 DynamoDB BatchGetItem — 從 shell 做同一件批次讀取。
- Node.js 中的 DynamoDB GetItem — 這裡批次化的那個單項目讀取。
- DynamoDB 的批次操作 — 限制、部分失敗,以及批次何時划算。
- 「Too many items requested for the BatchGetItem call」 — 一次請求超過 100 個鍵。
- 「Provided list of item keys contains duplicates」 — 同一批次中同一個鍵出現兩次。
參考資料
- BatchGetItem — Amazon DynamoDB API Reference
- Error handling with DynamoDB — Amazon DynamoDB Developer Guide
- DynamoDB read and write operations (capacity unit consumption) — Amazon DynamoDB Developer Guide
最後查證於 2026-07-28,對照上方連結的官方 AWS 文件。