Golang从PostgreSQL中获取JSON数据时遇到问题
Golang从PostgreSQL中获取JSON数据时遇到问题 大家好 😊 我正在做一个好玩的API,但在尝试从数据库获取测试条目时遇到了问题。可能是我数据填充错了,也可能是我全做错了……我也不确定。
以下是我试图检索的内容:
type Config struct {
ID int `json:"id"`
Name string `json:"name"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Plan Plan `json:"plan"`
}
type Plan struct {
Name string `json:"name"`
Steps []Instruction `json:"steps"`
}
从Go得到的错误是:Scan error on column index 3, name “plan”: pq: destination *data.Plan is not a pointer to array or slice
以下是查询语句:
q := `select id, created_at, updated_at, plan from configurations`
rows, err := db.QueryContext(ctx, q)
if err != nil {
return nil, err
}
defer rows.Close()
var configs []*Config
for rows.Next() {
var cfg Config
err := rows.Scan(
&cfg.ID,
&cfg.CreatedAt,
&cfg.UpdatedAt,
// &cfg.Plan,
pq.Array(&cfg.Plan),
)
if err != nil {
return nil, err
}
configs = append(configs, &cfg)
}
以下是我尝试以JSONB格式存储在数据库中的JSON:
1 {
2 "name": "jabber",
3 "steps": [{
4 "id": 1,
5 "name": "first",
6 "hosts": ["fake1", "fake2"],
7 "command": "putup",
8 "fatal": false,
9 "timeout": 62
10 }]
11
12 }
非常感谢!
更多关于Golang从PostgreSQL中获取JSON数据时遇到问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html
我认为这能解决问题,非常感谢。
更多关于Golang从PostgreSQL中获取JSON数据时遇到问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
你好 @rexlx,
数据库的 plan 列似乎包含了你发布的 JSON 字符串,对吗?代码试图将这个 JSON 字符串扫描到类型为 Plan(一个结构体类型)的字段中。
我建议尝试将 plan 列扫描到一个字符串中,然后将该字符串解组到 Plan 和 Instructions 结构体中(使用 encoding/json)。
问题出在数据库中的plan列是JSONB类型,而你在Go代码中试图使用pq.Array()来扫描它。pq.Array()只适用于PostgreSQL的数组类型,不适用于JSONB类型。
你需要将plan列作为JSON字符串扫描,然后手动解析到Plan结构体。以下是修改后的代码:
import (
"database/sql"
"encoding/json"
"time"
)
type Config struct {
ID int `json:"id"`
Name string `json:"name"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Plan Plan `json:"plan"`
}
type Plan struct {
Name string `json:"name"`
Steps []Instruction `json:"steps"`
}
type Instruction struct {
ID int `json:"id"`
Name string `json:"name"`
Hosts []string `json:"hosts"`
Command string `json:"command"`
Fatal bool `json:"fatal"`
Timeout int `json:"timeout"`
}
func GetConfigs(ctx context.Context, db *sql.DB) ([]*Config, error) {
q := `SELECT id, created_at, updated_at, plan FROM configurations`
rows, err := db.QueryContext(ctx, q)
if err != nil {
return nil, err
}
defer rows.Close()
var configs []*Config
for rows.Next() {
var cfg Config
var planJSON []byte
err := rows.Scan(
&cfg.ID,
&cfg.CreatedAt,
&cfg.UpdatedAt,
&planJSON,
)
if err != nil {
return nil, err
}
// 解析JSON到Plan结构体
var plan Plan
if err := json.Unmarshal(planJSON, &plan); err != nil {
return nil, err
}
cfg.Plan = plan
configs = append(configs, &cfg)
}
return configs, nil
}
如果你使用的是PostgreSQL 14+,也可以使用jsonb_populate_record函数直接在查询中处理:
func GetConfigsWithJSONB(ctx context.Context, db *sql.DB) ([]*Config, error) {
q := `
SELECT
id,
created_at,
updated_at,
jsonb_populate_record(null::record, plan)::jsonb as plan
FROM configurations
`
rows, err := db.QueryContext(ctx, q)
if err != nil {
return nil, err
}
defer rows.Close()
var configs []*Config
for rows.Next() {
var cfg Config
var planJSON []byte
err := rows.Scan(
&cfg.ID,
&cfg.CreatedAt,
&cfg.UpdatedAt,
&planJSON,
)
if err != nil {
return nil, err
}
var plan Plan
if err := json.Unmarshal(planJSON, &plan); err != nil {
return nil, err
}
cfg.Plan = plan
configs = append(configs, &cfg)
}
return configs, nil
}
如果你使用sqlx库,处理会更简单:
import "github.com/jmoiron/sqlx"
func GetConfigsWithSqlx(ctx context.Context, db *sqlx.DB) ([]*Config, error) {
var configs []*Config
err := db.SelectContext(ctx, &configs,
`SELECT id, created_at, updated_at, plan FROM configurations`)
return configs, err
}
确保你的数据库表结构正确创建了JSONB列:
CREATE TABLE configurations (
id SERIAL PRIMARY KEY,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
plan JSONB NOT NULL
);

