#5 PostgreSQL 与 MySQL 的 JSON 类型:Go 项目怎么选
MySQL PostgreSQL JSON 2026-09-14关系型数据库支持 JSON 已经很成熟,但 JSON 并不意味着可以随意替代普通字段。实际项目中,更重要的问题是:PostgreSQL 的 json 和 jsonb 怎么选?MySQL JSON 如何建立索引?Go 又应该怎样读写?
coding in a complicated world
关系型数据库支持 JSON 已经很成熟,但 JSON 并不意味着可以随意替代普通字段。实际项目中,更重要的问题是:PostgreSQL 的 json 和 jsonb 怎么选?MySQL JSON 如何建立索引?Go 又应该怎样读写?
PostgreSQL 对 JSON 的支持不仅限于存储数据。实际开发中,jsonb 更常用,因为它会以二进制格式存储 JSON,并提供结构化查询、修改和索引能力。对于字段结构存在一定变化、但又希望直接利用数据库查询能力的业务数据,jsonb 是比较合适的方案。
在 Go 的 encoding/json 包中,json.RawMessage 是一个很实用的类型。它本质上是 []byte,用于保存一段未经解析的 JSON 数据,让程序可以延迟决定如何解析。
例如接口返回的数据中,data 字段可能对应不同结构:
type Response struct {
Code int `json:"code"`
Data json.RawMessage `json:"data"`
}
第一次 json.Unmarshal 时,Data 不会被解析成 map[string]any,而是直接保存原始 JSON。根据 Code 或其他字段确定具体类型后,再进行第二次解析:
var user User
if err := json.Unmarshal(resp.Data, &user); err != nil {
return err
}
这种方式特别适合多态 JSON、动态字段、消息路由和兼容不同版本的数据结构。
any 的区别如果使用 any 接收 JSON,就相当于把内容当作 map[string]any 解析,其中数字解析为 float64,导致类型信息丢失。
json.RawMessage 则保留 JSON 原文,可以在真正需要时再决定目标类型,也避免了不必要的解析。
type Response struct {
Type string `json:"type"`
Data any `json:"data"`
}
{
"type": "user",
"data": {
"id": 123,
"name": "Woody"
}
}
// map[string]any{
// "id": float64(123),
// "name": "Woody",
// }
Golang 有一个 encoding/json 标准库,在多数情况下已经够用了。
注意:因为 Golang 是一种静态类型的语言,所以解析 JSON 字符串必须了解里面的数据结构。
如果是用惯了 JS、Python、PHP 等动态语言的话,到这里会有些郁闷,怎么解析一个 JSON 还这么复杂。
jq 是我在命令行中解析 JSON 的一个常用工具,用起来非常顺手。
curl https://24pullrequests.com/users.json | jq
# 取第一个元素
curl https://24pullrequests.com/users.json | jq '.[0]'
# 取第一个元素的指定字段
curl https://24pullrequests.com/users.json | jq '.[0].nickname'
# 切片
curl https://24pullrequests.com/users.json | jq '.[:2]'
# 遍历
curl https://24pullrequests.com/users.json | jq '.[] | .nickname'
# 取字段
curl https://24pullrequests.com/users/changeworld.json | jq .nickname
# 取多个字段
curl https://24pullrequests.com/users/changeworld.json | jq '.nickname,.contributions_count'
# 获取列表长度
curl https://24pullrequests.com/users.json | jq length
# 列出 Keys
curl https://24pullrequests.com/users/changeworld.json | jq keys
curl https://24pullrequests.com/users/changeworld.json | jq "keys[]"
curl https://24pullrequests.com/users.json | jq ".[0] | keys[]"
# 列出 Keys 和 值类型
cat a.json | jq ".[0] | keys,map(type)"
cat a.json | jq ".[0] | to_entries | map([.key, (.value | type)])"
cat a.json | jq '.[0] | to_entries | map("\(.key) : \(.value|type)")[]'
还有很多更强大的用法,可以参考文档,我就会上面几个,在命令行中简单搜索 JSON 也够用了。
刚在文档中学会一招,重新组合 JSON:
curl https://24pullrequests.com/users/changeworld.json | jq '[.nickname, .organisations[].login]'
curl https://24pullrequests.com/users/changeworld.json | jq '{name:.nickname, orgs:[.organisations[].login]}'
👍🏻 Nice!!!