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

在 AWS SDK v3 里,一次完整的 Query 是下面那个 do/while,而不是大多数代码片段展示的那一次 client.send():一页的上限是 1 MB,分区里剩下的部分只有在你把 LastEvaluatedKey 喂回去之后才会到。至于什么时候 Query 才是对的读取方式,见 Query 与 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" 之下,上面的循环发出了三次请求:

往返次数CountScannedCount读单元LastEvaluatedKey
1271271128.5
2271271128.5
3585827.5

没人配置过 271。那是 1 MB 用完的位置,所以只要你的项大小变了,页边界就会跟着挪。今天翻一页的分区,在你加一个属性之后就翻两页;而只从一次 send()response.Items 的代码,会在不报任何错的情况下把 600 首歌里的 271 首交给你。

现在给同一个查询加上 Limit: 10 和一个针对 YearFilterExpression

Count: 0   ScannedCount: 10   ConsumedCapacity: 5   LastEvaluatedKey: set

十个项被检查、零个被返回,而这次请求照样花了读容量。Limit 限制的是 DynamoDB 读取的量,过滤器是在那之后才跑的,所以一个按"给我 10 条结果"来设的 Limit,给你的是 0 到 10 条之间的任意数量。

2026-07-28 针对 DynamoDB Local(amazon/dynamodb-local)、在 node v24.18.0 上用 @aws-sdk/client-dynamodb 3.1095.0 测量。计数和容量都是引擎自己的响应字段。

说明

  • 第一轮的 ExclusiveStartKey: lastEvaluatedKeyundefined,而这是刻意的:v3 序列化器会丢掉 undefined 成员,所以同一个对象字面量对第一次请求和之后每一次都适用。换成 {}——"从头开始"最容易想到的猜法——会以 ValidationException: The provided starting key is invalid 失败。
  • @aws-sdk/client-dynamodb 从不替你编组。值以 {S: 'Arturo Sandoval'} 的形式进去,项也以同样的形式回来。这是不引入 DocumentClient 所付的代价;如果你更愿意写普通 JS 对象,该用的封装是 @aws-sdk/lib-dynamodb
  • 数字是以字符串的形式完成往返的。用 @aws-sdk/util-dynamodbunmarshall 解组 {N: '9007199254740993'} 得到的是一个 JS bigint,而不是有损的 number;传 {wrapNumbers: true} 则得到 {value: '9007199254740993'}。无论哪种,都不要对一个没做过大小检查的 DynamoDB N 调用 Number()
  • KeyConditionExpression 接收分区键上的一个相等条件,外加至多一个排序键条件(=<<=>>=BETWEENbegins_with)。其他任何东西都该放进 FilterExpression,而它是在读取之后才跑的。
  • ScanIndexForward: false 会反转排序键顺序;默认是升序。IndexName 能把同一条命令切换到某个二级索引上。

用可视化的方式来做

DynamoDB 查询构建器会把这整个形态——键条件、名字映射和值映射,以及那个 LastEvaluatedKey 循环——生成为一个可运行的 SDK v3 程序,于是分页就不再是你会忘掉的那一部分。

要在真实的表上用图形界面跑查询,配上键条件表单和分页结果表格,请下载 DynoTable

相关指南

参考资料

可视化构建此请求

在免费的 DynamoDB 查询构建器中组装此操作 —— 键条件、筛选、索引、Limit、排序方向和分页循环 —— 再把它作为可运行的 SDK v3、CLI 或 boto3 程序复制回来。

打开 DynamoDB 查询构建器

无需控制台即可使用 DynamoDB

一款快速的 DynamoDB 桌面客户端,可运行 DynamoDB 无法执行的真正 SQL——JOINs、GROUP BY、聚合——并支持可视化编辑和运行在你自己的 Bedrock 密钥上的 AI agent。

30 天免费试用,无需信用卡 — 之后为无时间限制的免费版。