Go使用pgx读取PostgreSQL的JSONB字段时如何定义结构体接收动态键
解决方案
方案1:使用map存储动态键值对(推荐)
因为user_roles下的键是动态的UID字符串,值为角色数组,直接将UserRoles字段声明为map[string][]string类型即可适配动态键:
type Data struct { UserRoles map[string][]string `json:"user_roles,omitempty"` } type MyTable struct { ID string Data Data }
方案2:适配pgx的JSONB反序列化逻辑
pgx默认无法直接将JSONB字段转换为自定义结构体,有两种处理方式可选:
方式A:先读取为字节数组再手动反序列化
import "encoding/json" // ... 省略其他初始化代码 sql := "SELECT id, data FROM mytable" // 建议同时查询id字段 myTable := new(MyTable) var dataBytes []byte // 按查询字段顺序Scan err = pg.QueryRow(context.Background(), sql).Scan(&myTable.ID, &dataBytes) if err != nil { // 处理查询错误 } // 反序列化字节数组为Data结构体 err = json.Unmarshal(dataBytes, &myTable.Data) if err != nil { // 处理反序列化错误 } fmt.Printf("%v", myTable.Data)
方式B:为Data类型实现pgx的Scanner接口
实现后可以直接将JSONB字段Scan到Data结构体,简化后续查询代码:
import ( "encoding/json" "errors" ) // 实现pgx Scanner接口 func (d *Data) Scan(src interface{}) error { source, ok := src.([]byte) if !ok { return errors.New("failed to assert src as []byte") } return json.Unmarshal(source, d) } // ... 后续查询可以直接Scan sql := "SELECT id, data FROM mytable" myTable := new(MyTable) err = pg.QueryRow(context.Background(), sql).Scan(&myTable.ID, &myTable.Data)
其他可选方案
如果不需要结构化处理JSONB内容,仅需要完整返回原始JSON,可以直接将Data字段声明为[]byte或json.RawMessage类型,无需反序列化直接使用。
内容的提问来源于stack exchange,提问作者Hongbo Miao
相关产品推荐
相关产品推荐

