用 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 254254 表示服务拒绝了,而不是 CLI 出了故障。AWS CLI 把 252/253 留给它自己的语法和配置问题,255 留给其他一切,所以 ConditionalCheckFailedException、ValidationException 和限流最终都落在同一个 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。
相关指南
- DynamoDB 条件表达式——
attribute_not_exists、乐观锁等等。 - DynamoDB 数据类型——每种属性类型在 DynamoDB JSON 里怎么写。
- DynamoDB ConditionalCheckFailedException——项目已存在时,仅创建的条件会抛出什么。
- DynamoDB ValidationException——格式错误的项目或表达式的万能兜底错误。
参考资料
- PutItem — Amazon DynamoDB API Reference
- put-item — AWS CLI Command Reference
- Understanding return codes — AWS CLI User Guide
- Condition expressions — Amazon DynamoDB Developer Guide
- Working with items and attributes — Amazon DynamoDB Developer Guide
2026-07-28 用 aws-cli/2.36.9 针对 9000 端口上的 DynamoDB Local(amazon/dynamodb-local)复现。退出码、错误文本和容量读数均为原样照录的输出。失败写入的容量说法是引自 AWS 文档而非实测:DynamoDB Local 在条件失败路径上不返回 ConsumedCapacity。