Node.js(AWS SDK v3)中的 DynamoDB Query
在 AWS SDK v3 中,一次完整的 Query 是下面那個 do/while,而不是多數程式碼片段所展示的單一 client.send():一頁上限是 1 MB,分割區的其餘部分只有在你把 LastEvaluatedKey 餵回去之後才會抵達。至於 Query 究竟是不是對的讀取方式,請見 Query vs. Scan。
程式碼
import {DynamoDBClient, QueryCommand} from '@aws-sdk/client-dynamodb';
const client = new DynamoDBClient({region: 'us-east-1'});
const items = [];
let lastEvaluatedKey;
do {
const response = await client.send(
new QueryCommand({
TableName: 'Music',
KeyConditionExpression: '#hashKey = :hashKeyValue AND begins_with(#rangeKey, :rangeKeyValue)',
ExpressionAttributeNames: {
'#hashKey': 'Artist',
'#rangeKey': 'SongTitle'
},
ExpressionAttributeValues: {
':hashKeyValue': {S: 'Arturo Sandoval'},
':rangeKeyValue': {S: 'C'}
},
ExclusiveStartKey: lastEvaluatedKey
})
);
items.push(...(response.Items ?? []));
lastEvaluatedKey = response.LastEvaluatedKey;
} while (lastEvaluatedKey);
console.log(`Found ${items.length} items`);這個迴圈實際上做了什麼
對一個 600 首歌的測試資料集執行,每首歌約 3.9 KB,全部落在 Artist = "Arturo Sandoval" 之下,上面的迴圈會送出三個請求:
| 來回 | Count | ScannedCount | 讀取單位 | LastEvaluatedKey |
|---|---|---|---|---|
| 1 | 271 | 271 | 128.5 | 有 |
| 2 | 271 | 271 | 128.5 | 有 |
| 3 | 58 | 58 | 27.5 | 無 |
沒有人設定過 271。那是 1 MB 用完的地方,所以只要你的項目大小一變,頁面邊界就跟著動。一個今天只分一頁的分割區,在你加了一個屬性之後就會分成兩頁,而從單一 send() 讀取 response.Items 的程式碼,會無聲地回傳 600 首歌中的 271 首,不報任何錯。
現在對同一個查詢加上 Limit: 10 與一個針對 Year 的 FilterExpression:
Count: 0 ScannedCount: 10 ConsumedCapacity: 5 LastEvaluatedKey: set評估了十個項目,回傳零個,而這個請求照樣花掉讀取容量。Limit 限制的是 DynamoDB 讀取的量,而 filter 是在那之後才執行,所以一個被當成「給我 10 筆結果」來設定的 Limit,給你的會是 0 到 10 筆之間。
已於 2026-07-28 在 node v24.18.0 上,以 @aws-sdk/client-dynamodb 3.1095.0 對照 DynamoDB Local(amazon/dynamodb-local)量測。各項計數與容量皆為引擎自身的回應欄位。
說明
ExclusiveStartKey: lastEvaluatedKey在第一輪是undefined,而那是刻意的:v3 序列化器會丟掉undefined的成員,所以同一個物件字面值對第一個請求與之後每一次續讀都適用。若把它換成{}— 那個「從頭開始」的直覺猜法 — 會以ValidationException: The provided starting key is invalid失敗。@aws-sdk/client-dynamodb從來不會替你 marshal。值以{S: 'Arturo Sandoval'}的形式進去,項目也以同樣的形式回來。那是不引入 DocumentClient 的代價;如果你寧可寫單純的 JS 物件,@aws-sdk/lib-dynamodb就是該拿來用的包裝。- 數字是以字串形式熬過這趟來回的。用
@aws-sdk/util-dynamodb的unmarshall解出{N: '9007199254740993'}會得到一個 JSbigint,而不是會失真的number;傳入{wrapNumbers: true}則會拿到{value: '9007199254740993'}。無論哪一種,都不要對一個你沒檢查過大小的 DynamoDBN直接呼叫Number()。 KeyConditionExpression接受一個對 partition key 的等值條件,外加至多一個 sort key 條件(=、<、<=、>、>=、BETWEEN、begins_with)。其他任何條件都屬於FilterExpression,而它是在讀取之後才執行。ScanIndexForward: false會反轉 sort key 的排序;預設是遞增。IndexName則能把同一個指令切換到某個 secondary index。
改用視覺化操作
DynamoDB 查詢建構器會把這整個形狀 — key 條件、名稱與值對應,以及 LastEvaluatedKey 迴圈 — 產生成一支可執行的 SDK v3 程式,於是分頁就不再是你會忘掉的那一塊。
若想在 GUI 中對真正的表格執行查詢,搭配 key 條件表單與分頁結果格線,請下載 DynoTable。
相關指南
- Query vs. Scan — 為什麼
Query才是正確的預設。 - Key condition 運算式 — 每一個合法的 partition/sort key 運算子。
- "Query condition missed key schema element" — key 條件指名了錯的屬性,或漏掉了 partition key。
- "Query key condition not supported" — key 條件不能用的運算子,像 contains 或第二個 sort key 條件。