SQLC检索JSONB存储数据遇阻:嵌套JSON解析及类型生成问题
JSONB字段解析与SQLC类型生成问题
表结构定义
我有一个包含JSONB类型字段的PostgreSQL表,结构如下:
CREATE TABLE IF NOT EXISTS "test_table" ( "id" text NOT NULL, "user_id" text NOT NULL, "content" jsonb NOT NULL, "create_time" timestamptz NOT NULL, "update_time" timestamptz NOT NULL, PRIMARY KEY ("id") );
SQLC代码生成情况
我用SQLC执行如下查询生成Go代码:
-- name: GetTestData :one SELECT * FROM test_table WHERE id = $1 LIMIT 1;
生成的TestTable结构体中,Content字段被定义为json.RawMessage:
type TestTable struct { ID string `json:"id"` UserId string `json:"user_id"` Content json.RawMessage `json:"content"` CreateTime time.Time `json:"create_time"` UpdateTime time.Time `json:"update_time"` }
Content字段的JSON示例
content列存储的JSON结构如下:
{ "static": { "product": [ { "id": "string", "elements": { "texts": [ { "id": "string", "value": "string" } ], "colors": [ { "id": "string", "value": "string" } ], "images": [ { "id": "string", "values": [ { "id": "string", "value": "string" } ] } ] } } ] }, "dynamic": { "banner": [ { "id": "string", "elements": { "texts": [ { "id": "string", "value": "string" } ], "colors": [ { "id": "string", "value": "string" } ], "images": [ { "id": "string", "values": [ { "id": "string", "value": "string" } ] } ] } } ] } }
解析失败的尝试
我尝试解析Content字段但未能成功,代码如下:
var res map[string]json.RawMessage if err := json.Unmarshal(testingData.Content, &res); err != nil { return nil, status.Errorf(codes.Internal, "Serving data err %s", err) } var static pb.Static if err := json.Unmarshal(res["Static"], &static); err != nil { return nil, status.Errorf(codes.Internal, "Static data err %s", err) } var dynamic pb.Dynamic if err := json.Unmarshal(res["Dynamic"], &dynamic); err != nil { return nil, status.Errorf(codes.Internal, "Dynamic data err %s", err) }
解决方案
1. 修复解析代码的错误
解析失败的核心原因是JSON键名大小写不匹配:JSON中的键是小写的static和dynamic,但代码中用了大写开头的res["Static"]、res["Dynamic"],导致无法找到对应数据。
修正后的代码:
var res map[string]json.RawMessage if err := json.Unmarshal(testingData.Content, &res); err != nil { return nil, status.Errorf(codes.Internal, "解析数据失败: %s", err) } var static pb.Static if err := json.Unmarshal(res["static"], &static); err != nil { return nil, status.Errorf(codes.Internal, "解析Static数据失败: %s", err) } var dynamic pb.Dynamic if err := json.Unmarshal(res["dynamic"], &dynamic); err != nil { return nil, status.Errorf(codes.Internal, "解析Dynamic数据失败: %s", err) }
同时需要确保pb.Static和pb.Dynamic结构体的JSON标签与JSON结构完全匹配(比如Static结构体的product字段要有json:"product"标签)。
2. 让SQLC直接生成自定义类型
通过SQLC的配置文件,可以指定JSONB字段对应的Go类型,避免手动Unmarshal操作:
- 在项目根目录创建
sqlc.yaml配置文件,添加类型映射规则:
version: "2" sql: - schema: "schema.sql" queries: "queries.sql" engine: "postgresql" gen: go: package: "db" out: "db" overrides: - db_type: "jsonb" go_type: "yourpackage.ContentStruct" # 替换为你的自定义结构体路径 # 若需直接映射为map类型,可改为: # go_type: "map[string]interface{}"
- 定义与JSON结构匹配的自定义结构体(示例):
package yourpackage type ContentStruct struct { Static StaticContent `json:"static"` Dynamic DynamicContent `json:"dynamic"` } type StaticContent struct { Product []Product `json:"product"` } type DynamicContent struct { Banner []Product `json:"banner"` } type Product struct { ID string `json:"id"` Elements Elements `json:"elements"` } type Elements struct { Texts []Text `json:"texts"` Colors []Color `json:"colors"` Images []Image `json:"images"` } type Text struct { ID string `json:"id"` Value string `json:"value"` } type Color struct { ID string `json:"id"` Value string `json:"value"` } type Image struct { ID string `json:"id"` Values []ImageValue `json:"values"` } type ImageValue struct { ID string `json:"id"` Value string `json:"value"` }
重新运行SQLC生成代码后,TestTable的Content字段会直接是你定义的ContentStruct类型,无需手动解析。
内容的提问来源于stack exchange,提问作者Mido
相关产品推荐
相关产品推荐

