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类型正好只有两个可选成员,PutRequest和DeleteRequest,两个都不接受ConditionExpression或ReturnValues。这并不是 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,也覆盖一个 put+delete 的组合——第一次看到时会觉得别扭。 - 整批被拒的清单比显而易见的那三条要长。除了超过 25 个请求、单个项目超过 400 KB 和总体超过 16 MB,DynamoDB 还会因为表不存在、键与模式不匹配、分区键超过 2048 字节或排序键超过 1024 字节而拒绝整个批次。一个坏条目让你赔上全部 25 个。
- 批量买到的是往返次数,不是容量。每个条目都按一次独立的
PutItem或DeleteItem计费,向上取整到 1 KB,而且一次针对不存在项目的删除照样消耗一个写入单元。
只带键的 PutRequest 会毁掉项目的其余部分
Ella Fitzgerald / Misty 一开始是带着 AlbumTitle 和 Year 的。发一个只带那两个键属性的 PutRequest:
{PutRequest: {Item: {Artist: {S: 'Ella Fitzgerald'}, SongTitle: {S: 'Misty'}}}}然后用 ConsistentRead: true 把它读回来。DynamoDB Local 3.3.0 返回:
{
"Artist": { "S": "Ella Fitzgerald" },
"SongTitle": { "S": "Misty" }
}AlbumTitle 和 Year 没了。调用成功了,UnprocessedItems 是 {},响应里没有任何东西提到它丢掉的那两个属性。put 是整项目替换,所以一个由部分负载拼出来的批次(一个 API 请求体、一个 CSV 列子集、一个省略了属性的投影 Query 结果)会抹掉负载里没带的每一个属性。
当你把批量拿来做感觉上像更新的事情时,这就是你要预先防住的失败模式。修法是先把当前项目读出来再合并,或者干脆别用批量、改用 UpdateItem——它只碰你点名的那些属性。
一个 25 项的批次变成 12 项的另一个原因是大小。写入按每 1 KB 向上取整计费,而请求上限是 16 MB,所以一个项目真实的字节数同时决定了你的账单和能塞进几个。项目大小计算器会在你拼装这个数组之前,把每个项目的那个数字给你。
想批量加载、编辑和删除项目,又不想手写替换语义,就下载 DynoTable。
相关示例
- Python 中的 DynamoDB 批量写入——boto3 的
batch_writer()替你做重试循环。 - 用 AWS CLI 执行 DynamoDB BatchWriteItem——从命令行做同样的批量写入。
- Node.js 中的 DynamoDB TransactWriteItems——当这些写入必须一起成功或一起失败时。
- DynamoDB 批量操作——限制、部分失败,以及批量在什么时候划算。
- "Too many items requested for the BatchWriteItem call"——一个批次里超过 25 个 put/delete 请求。
- "Provided list of item keys contains duplicates"——一个批次里有两个请求碰到了同一个键。
参考资料
- BatchWriteItem — 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 官方文档。