DynamoDB JSON 与 Marshalling
你第一次从 DynamoDB API 读到原始数据时,它看起来不像你放进去的那个 JSON。一个像
{"status": "open", "priority": 3} 的普通对象,返回时成了
{"status": {"S": "open"}, "priority": {"N": "3"}}。每个值都被包进一个标明其类型的单键对象里。
那层包裹就是 DynamoDB JSON,而在它与普通形式之间来回转换,叫作 marshalling。
这不是噪声 —— 这是 DynamoDB 在传输线上保持类型无歧义的方式。但它会绊倒任何期待普通 JSON 的人, 而手写它又容易出错。
什么是 DynamoDB JSON?
DynamoDB JSON 是 DynamoDB 使用的带类型标签的传输格式,其中每个值都被包裹在一个标明其类型的单键对象里 —— 字符串用 {"S": "open"},数字用 {"N": "3"}。在普通 JSON 与它之间来回转换的过程叫作 marshalling。这套格式让类型始终无歧义,因为普通 JSON 无法表达集合、二进制,也无法区分字符串 "3" 和数字 3。
- DynamoDB JSON 给每个值都标上它的类型 —— 字符串用
{"S": "..."},数字用{"N": "..."}, 依此类推。 - Marshalling = 普通 JSON → DynamoDB JSON。Unmarshalling = 反过来。
- 数字在传输线上是字符串 ——
{"N": "3"},而非{"N": 3}—— 以保留精度。 - 那些类型标签就是你早已在用来建模的数据类型系统:S、N、B、BOOL、NULL、L、M、SS、NS、BS。
- 别手写它。 SDK 的文档客户端(或一个转换器)会替你做 marshalling;只有在调试或构建表达式时 才手动去做。
问题所在:普通 JSON 不够用
JSON 恰好只有三种标量 —— 字符串、数字、布尔值 —— 外加 null、数组和对象。DynamoDB 有更多:二进制,
以及三种 JSON 根本无法表达的集合类型(字符串集合、数字集合、二进制集合)。JSON 也分不清一个
字符串 "3" 和一个数字 3,或者一个列表和一个集合。
所以 DynamoDB 不能原样存下你的 JSON —— 它需要每个值的确切类型被显式说明。类型描述符就是它做到 这一点的方式,无损地,在每一次请求和响应上。
这套编码如何工作
每个属性值都变成一个单键对象,其键是一个类型描述符:
| 描述符 | 类型 | 示例 |
|---|---|---|
S | 字符串 | {"S": "open"} |
N | 数字(作为字符串) | {"N": "3"} |
B | 二进制 | {"B": "dGV4dA=="} |
BOOL | 布尔值 | {"BOOL": true} |
NULL | 空值 | {"NULL": true} |
L | 列表 | {"L": [{"S": "a"}, {"N": "1"}]} |
M | 映射 | {"M": {"k": {"S": "v"}}} |
SS / NS / BS | 字符串/数字/二进制集合 | {"SS": ["a", "b"]} |
列表和映射把同样的描述符一路嵌套到底,所以一个结构很深的项就被包裹得很深。数字在传输线上是 字符串,这是有意为之 —— 它让 DynamoDB 能保留任意精度,而一个 JSON 数字(一个 IEEE-754 双精度) 会悄悄把它舍入掉。这些就是你用来建模的同一套数据类型;DynamoDB JSON 不过是 它们在传输线上的显式形态,定义在 AWS 底层 API 参考中。
实战示例:一条审计日志条目
你会在应用里写的普通 JSON:
{
"actor": "u-204",
"action": "ticket.close",
"ticketId": 8842,
"tags": ["billing", "urgent"],
"redacted": false
}为 API 而 marshal 成的 DynamoDB JSON:
{
"actor": {"S": "u-204"},
"action": {"S": "ticket.close"},
"ticketId": {"N": "8842"},
"tags": {"SS": ["billing", "urgent"]},
"redacted": {"BOOL": false}
}注意 marshaller 做出的选择:ticketId 变成了 N,值是一个字符串;tags 变成了一个字符串
集合(SS),而不是一个列表 —— 这是一个刻意的决定,因为集合会去重且无序。tags 该是 SS
还是 L,是一个转换器无法替你做的建模抉择,而这恰恰是为什么理解这套编码很重要。
在 DynoTable 中转换
你很少需要手写或手读它。把普通 JSON 粘进 DynamoDB JSON 转换器来 marshal 它(以及反向),而当你在组装 一个请求时,DynamoDB 表达式构建器会在表达式旁边一并输出 正确 marshal 好的属性值映射。在应用本身里,DynoTable 把项展示为普通、可读的值,并在写入时替你 marshal 它们。

坑与后续步骤
- 在 DynamoDB JSON 里数字是字符串 ——
{"N": "3"}。引号很要紧;别输出一个裸数字。 - 集合还是列表是一个建模决定,被这套编码摆到了明面上 —— 要刻意选择(见数据类型)。
- 在应用代码里优先用 SDK 文档客户端,而非手动 marshalling;把手写 DynamoDB JSON 留给调试和 表达式。
- 空字符串在项里是被允许的,但历来会绊倒一些工具 —— 验证边界情形。
想把项当作普通值来浏览,而不是用肉眼解码类型标签? 下载 DynoTable,直接处理你的数据。


