用 AWS CLI 做 DynamoDB PutItem

aws dynamodb put-item 会写入一个完整的项目,并替换掉任何具有相同主键的既有项目(基于项目的操作讲了它与 update-item 的区别)。CLI 自己额外贡献的麻烦是 shell:--item 接受作为单个带引号参数的 DynamoDB JSON,而且每一个属性值都是带类型的。

代码

aws dynamodb put-item \
  --table-name 'Music' \
  --item '{"Artist":{"S":"Arturo Sandoval"},"SongTitle":{"S":"Cubano Chant"},"AlbumTitle":{"S":"Danzon"},"Year":{"N":"1994"},"Awards":{"N":"0"}}' \
  --condition-expression 'attribute_not_exists(#cond0) AND attribute_not_exists(#cond1)' \
  --expression-attribute-names '{"#cond0":"Artist","#cond1":"SongTitle"}'

成功时命令什么也不打印,退出码为 0。如果项目已经存在,条件就会失败:

An error occurred (ConditionalCheckFailedException) when calling the PutItem operation:
The conditional request failed

说明

静默加退出码 0 是唯一的成功信号。除非你要求 --return-values,否则 put-item 不会打印任何 JSON,所以一个靠 grep 标准输出来确认的脚本永远不会触发。请检查 $?。在 aws-cli/2.36.9 上把上面那条命令跑两遍,得到:

first run:   (no output)                exit 0
second run:  aws: [ERROR]: An error occurred (ConditionalCheckFailedException) when calling the PutItem operation: The conditional request failed
             exit 254

254 表示服务拒绝了,而不是 CLI 出了故障。AWS CLI 把 252/253 留给它自己的语法和配置问题,255 留给其他一切,所以 ConditionalCheckFailedExceptionValidationException 和限流最终都落在同一个 254 上。如果你的脚本需要把预期中的条件失败与真正的故障区分开,请解析错误名,而不是退出码。另外注意 2.36.9 会给消息加上 aws: [ERROR]: 前缀,而更早的版本没有;一个锚定在 ^An error occurred 的正则会在 CLI 升级之后悄悄不再匹配。

失败的条件写入照样要花钱。条件是服务在定位到项目之后才求值的,而 AWS 明确写着「如果表达式求值为 false,DynamoDB 仍会消耗表的写容量单元」(抓取于 2026-07-28)。围绕一次仅创建的 put 做重试循环,每一次尝试都会计费。给个量级参考:对一个约 15 KB 的项目成功执行 put 时加上 --return-consumed-capacity TOTAL,报告的是 "CapacityUnits": 15。写入按 1 KB 取整,而不是读取用的 4 KB。

--return-values-on-condition-check-failure 能用,但 CLI 把答案藏了起来。正是这个参数能告诉你是_哪个_项目挡住了写入,而不必再读一次。加上它,2.36.9 打印的是:

aws: [ERROR]: An error occurred (ConditionalCheckFailedException) when calling the PutItem operation: The conditional request failed

Additional error details:
Item: <complex value>
Use "--cli-error-format json" or another error format to see the full details.

项目自始至终都在响应里;是默认的错误格式化器拒绝把它渲染出来。加上 --cli-error-format json 就能拿到。(--return-values ALL_OLD 是它的无条件表亲,只在成功时触发;ReturnValues讲了那五个取值。)

引号是这活儿的另一半--item 参数是一个 shell token,里面装着 JSON,JSON 里又装着带引号的数字({"N": "1994"},绝不是 1994)。任何含撇号的内容,以及任何超过几百字节的项目,写成 --item file://song.json 都更省事。--cli-input-json file://request.json 更进一步,接收整个请求(包括条件表达式),这也是评审时可以直接 diff 的形式。

这些别名不是可有可无的装饰#cond0/#cond1 通过 --expression-attribute-names 解析到 Artist/SongTitle。把名字直接写在表达式里一直能用,直到其中一个撞上保留字,那时命令会在一个你根本没改过的名字上失败。

用可视化的方式来做

手敲 --item 需要的带类型 JSON,是大多数这类命令翻车的地方。免费的 DynamoDB JSON 转换器把普通 JSON 转成这个参数想要的 {"S": …} / {"N": …} 形式,直接可以存成 file:// 载荷。

要针对你自己的表添加和编辑项目——每个属性一个表单字段、类型选择器、把结果作为 CLI 命令复制出来——请下载 DynoTable

相关指南

参考资料

2026-07-28 用 aws-cli/2.36.9 针对 9000 端口上的 DynamoDB Local(amazon/dynamodb-local)复现。退出码、错误文本和容量读数均为原样照录的输出。失败写入的容量说法是引自 AWS 文档而非实测:DynamoDB Local 在条件失败路径上不返回 ConsumedCapacity

无需控制台即可使用 DynamoDB

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

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