You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用sqlc向PostgreSQL jsonb字段插入[]byte数组失败求助

解决sqlc生成[]byte类型存入PostgreSQL jsonb字段报错问题

问题背景

我是Go与sqlc的新手,PostgreSQL数据库中有一个jsonb字段。执行sqlc generate后生成的类型为[]byte数组(与sqlc文档描述一致),但调用生成的插入函数将[]byte存入该字段时,抛出“Not a valid JSON type”错误。由于生成代码不能修改(重新生成会覆盖),我尝试让sqlc生成自定义类型而非[]byte,但不清楚如何将自定义结构体转换为PostgreSQL可接受的jsonb格式。

相关代码

sqlc生成配置SQL

-- name: CreateTeamUser :one
INSERT INTO team_users (
    meta_jsonb
) VALUES (
  $1
) RETURNING *;

生成的Go代码

type CreateTeamUserParams struct {
    Meta_jsonb   []byte      `json:"meta_jsonb"`
}

func (q *Queries) CreateTeamUser(ctx context.Context, arg CreateTeamUserParams) (TeamUser, error) {
    row := q.db.QueryRow(ctx, createTeamUser,
        arg.Meta_jsonb,
    )
    var i TeamUser
    err := row.Scan(
        &i.ID,
        &i.Meta_jsonb
    )
    return i, err
}

调用代码

arg := db.CreateTeamUserParams{
            Meta_jsonb:   user.GetMeta_Jsonb(),
        }

_, err := server.store.CreateTeamUser(ctx, arg)

传入的数据

{"meta_jsonb": {"name": "me"}}

报错信息

ERR received a HTTP request body="{\"code\":13,\"message\":\"failed to create user: ERROR: invalid input syntax for type json (SQLSTATE 22P02)\"}"

解决方案

方案一:手动序列化结构体为合法JSON字节流

报错的核心原因是user.GetMeta_Jsonb()返回的不是合法的JSON格式字节数组(比如直接返回了Go结构体而非序列化后的字节)。只需将结构体序列化为JSON字节再传入即可:

import "encoding/json"

// ...

metaData := user.GetMeta_Jsonb()
metaBytes, err := json.Marshal(metaData)
if err != nil {
    // 处理序列化错误,比如返回HTTP 400
}

arg := db.CreateTeamUserParams{
    Meta_jsonb: metaBytes,
}

_, err = server.store.CreateTeamUser(ctx, arg)

方案二:让sqlc生成自定义类型并自动处理转换

通过定义实现driver.Valuer和sql.Scanner接口的自定义类型,让sqlc自动完成Go类型与PostgreSQL jsonb的转换:

  1. 定义自定义类型(放在sqlc生成的包目录下,比如db/types.go):
package db

import (
    "database/sql/driver"
    "encoding/json"
    "errors"
)

// 替换成你的结构体字段
type Meta struct {
    Name string `json:"name"`
    // 其他需要的字段
}

// Value 将Meta转换为数据库可接受的JSON字节
func (m Meta) Value() (driver.Value, error) {
    return json.Marshal(m)
}

// Scan 将数据库返回的jsonb字节转换为Meta类型
func (m *Meta) Scan(value interface{}) error {
    bytes, ok := value.([]byte)
    if !ok {
        return errors.New("无法将值转换为Meta类型")
    }
    return json.Unmarshal(bytes, m)
}
  1. 修改sqlc配置文件(sqlc.yaml),添加类型映射:
version: "2"
sql:
  - schema: "schema.sql"
    queries: "queries.sql"
    engine: "postgresql"
    gen:
      go:
        package: "db"
        out: "db"
        overrides:
          - column: "team_users.meta_jsonb"
            go_type: "Meta"
  1. 重新生成代码
    执行sqlc generate后,生成的CreateTeamUserParams中Meta_jsonb的类型会变为Meta,调用时直接传入结构体即可:
arg := db.CreateTeamUserParams{
    Meta_jsonb: db.Meta{Name: "me"},
}

_, err := server.store.CreateTeamUser(ctx, arg)

内容的提问来源于stack exchange,提问作者The Keeper

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 16:43:19