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,也覆盖一个 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 agent。

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