Golang中如何将JSONB文本解析为[]string切片?
解决Golang中PGXPool+Squirrel解析JSONB到[]string的问题
问题原因
你用->>操作符从JSONB中取出的结果是文本格式的JSON数组字符串(例如["dev", "manager"]),而pgx默认无法直接将这种字符串类型自动映射为Go的[]string类型,因此扫描时抛出类型不匹配错误。
解决方案
以下三种方法都可以解决这个问题,根据你的场景选择:
方法1:使用pgx的JSONB类型中转
借助pgtype.JSONB先接收查询结果,再手动反序列化为[]string:
import ( "github.com/jackc/pgx/v5/pgtype" "encoding/json" ) type incompleteEntry struct { // ... 其他字段 EmployeePositionIDs pgtype.JSONB } // 在扫描后处理 for rows.Next() { var item incompleteEntry err := rows.Scan( // ... 其他字段 &item.EmployeePositionIDs, ) if err != nil { return nil, err } // 转成[]string var posIDs []string if item.EmployeePositionIDs.Status == pgtype.Present { err = json.Unmarshal(item.EmployeePositionIDs.Bytes, &posIDs) if err != nil { return nil, err } // 之后使用posIDs即可 } }
方法2:修改SQL查询,直接返回PostgreSQL文本数组
利用PostgreSQL 12+提供的jsonb_array_to_text_array函数,将JSONB数组直接转换为PostgreSQL的text[]类型,pgx可以直接映射为Go的[]string:
query := sq.StatementBuilder. PlaceholderFormat(sq.Dollar). Select( // ... 其他字段 "jsonb_array_to_text_array(logbooks.stages -> logbook_entries.next_stage_id -> 'employee_position_ids') as employee_position_ids", ). From("logbook_entries"). Join("logbooks on logbooks.id = logbook_entries.logbook_id and logbooks.current_version=logbook_entries.logbook_version"). // ... 其他查询条件
修改后直接扫描到[]string字段即可,无需额外处理。
方法3:自定义扫描类型
实现sql.Scanner接口,让自定义类型自动处理JSON字符串到[]string的解析:
import ( "encoding/json" "fmt" "database/sql" ) // 自定义类型,用于接收JSON数组字符串并转为[]string type StringSlice []string func (s *StringSlice) Scan(value interface{}) error { // 先把数据库返回的结果转为字符串 strVal, ok := value.(string) if !ok { return fmt.Errorf("failed to scan: expected string, got %T", value) } // 空字符串直接返回空切片 if strVal == "" { *s = []string{} return nil } // 反序列化为[]string return json.Unmarshal([]byte(strVal), s) } // 修改结构体字段类型 type incompleteEntry struct { // ... 其他字段 EmployeePositionIDs StringSlice } // 扫描时直接使用 for rows.Next() { var item incompleteEntry err := rows.Scan( // ... 其他字段 &item.EmployeePositionIDs, ) if err != nil { return nil, err } // item.EmployeePositionIDs已经是[]string类型,可以直接使用 }
内容的提问来源于stack exchange,提问作者Alexandr Rutkowski
相关产品推荐
相关产品推荐

