DynamoDB JSON 與 Marshalling
你第一次從 DynamoDB API 讀出原始資料時,它看起來不像你放進去的 JSON。一個像 {"status": "open", "priority": 3} 的普通物件,回來時成了 {"status": {"S": "open"}, "priority": {"N": "3"}}。每個值都被包進一個單鍵物件,標明它的型別。那層包裝就是 DynamoDB JSON,而在它與普通 JSON 之間來回轉換,稱為 marshalling。
它不是雜訊 — 它是 DynamoDB 在傳輸上讓型別不含糊的方式。但它會絆倒任何期待普通 JSON 的人,而手寫它很容易出錯。
什麼是 DynamoDB JSON?
DynamoDB JSON 是 DynamoDB 使用的帶型別標記的傳輸格式,每個值都被包進一個單鍵物件來標明其型別 — 字串用 {"S": "open"},數字用 {"N": "3"}。在普通 JSON 與 DynamoDB 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 的 document client(或一個轉換器)會替你 marshal;只在除錯或建構運算式時才手動做。
問題:普通 JSON 不夠用
JSON 恰好只有三種純量 — 字串、數字、布林 — 外加 null、陣列與物件。DynamoDB 有更多:二進位,以及三種 set 型別(字串集合、數字集合、二進位集合),那是 JSON 根本無法表達的。JSON 也分不出字串 "3" 與數字 3,或一個串列與一個集合。
所以 DynamoDB 不能就這樣原封不動地存你的 JSON — 它需要每個值的確切型別被明確陳述。型別描述符就是它做這件事的方式,在每個請求與回應上都無損地進行。
編碼如何運作
每個屬性值都變成一個單鍵物件,其鍵是一個型別描述符:
| 描述符 | 型別 | 範例 |
|---|---|---|
S | 字串 | {"S": "open"} |
N | 數字(以字串表示) | {"N": "3"} |
B | 二進位 | {"B": "dGV4dA=="} |
BOOL | 布林 | {"BOOL": true} |
NULL | Null | {"NULL": true} |
L | 串列 | {"L": [{"S": "a"}, {"N": "1"}]} |
M | Map | {"M": {"k": {"S": "v"}}} |
SS / NS / BS | 字串/數字/二進位集合 | {"SS": ["a", "b"]} |
串列與 map 把相同的描述符一路向下巢狀,所以一個結構很深的項目就變成包裝很深。數字刻意以字串在傳輸上行進 — 這讓 DynamoDB 能保留任意精度,而一個 JSON 數字(一個 IEEE-754 double)會悄悄把它捨入。這些就是你拿來建模的同一批資料型別;DynamoDB JSON 只是它們明確的傳輸形式,定義在 AWS 低階 API 參考裡。
實作範例:一筆稽核記錄條目
你會在 app 裡寫的普通 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 好的屬性值對照一起發出。在 app 本身裡,DynoTable 把項目顯示為普通、可讀的值,並在寫入時替你 marshal。

陷阱與下一步
- 數字在 DynamoDB JSON 裡是字串 —
{"N": "3"}。引號很重要;別發出一個裸數字。 - 集合與串列之爭是一個建模決定,而這套編碼把它攤在眼前 — 慎重地挑(請見資料型別)。
- 在 app 程式碼裡,偏好 SDK 的 document client 而非手動 marshalling;把手寫 DynamoDB JSON 留給除錯與運算式。
- 空字串是被允許的,在項目裡,但歷來會絆倒一些工具 — 驗證邊界情況。
想把項目當成普通值瀏覽,而不是用眼睛解碼型別標記嗎?下載 DynoTable,直接處理你的資料。


