【问题标题】:Nested JSON result in Golang from Postgres从 Postgres 到 Golang 的嵌套 JSON 结果
【发布时间】:2023-04-08 00:11:01
【问题描述】:

我正在使用gingorp

SQL:

SELECT p.project_id, p.name, 

COALESCE(NULLIF(json_agg(a.*)::TEXT, '[null]'), '[]')::JSON AS apps 

FROM project p LEFT JOIN app a USING (project_id) 

WHERE p.user_id=19 

GROUP BY p.project_id, p.name ORDER BY project_id

结果:

Golang

type Project struct {
    ID        int64           `db:"project_id, primarykey, autoincrement" json:"id"`
    UserID    int64           `db:"user_id" json:"user_id"`
    Name      string          `db:"name" json:"name"`
    Status    int             `db:"status" json:"status"`
    UpdatedAt int64           `db:"updated_at" json:"updated_at"`
    CreatedAt int64           `db:"created_at" json:"created_at"`
    Apps      json.RawMessage `json:"apps"`
}


func GetProjects(userID int64, page string) []Project {
    var projects []Project

    var err error
    _, err = db.GetDB().Select(&projects, "SELECT p.project_id, p.name, COALESCE(NULLIF(json_agg(a.*)::TEXT, '[null]'), '[]')::JSON AS apps FROM project p LEFT JOIN app a USING (project_id) WHERE p.user_id=$1 GROUP BY p.project_id, p.name ORDER BY project_id LIMIT 10 OFFSET $2", userID, page)
    fmt.Println("err", err)

    return projects
}

并使用以下命令返回结果:c.JSON(200, gin.H{"data": projects})

如果只有一个项目就可以了

但如果有多个项目,则会出现以下错误:

错误:json: error calling MarshalJSON for type json.RawMessage: invalid character '"' after top-level value

有什么建议吗?

P.S:我是 Golang 的新手

【问题讨论】:

  • json.RawMessage 上的方法都采用指针接收器。您是否尝试添加Apps *json.RawMessage ...

标签: json data-structures go struct go-gin


【解决方案1】:

您可以使用此站点http://json2struct.mervine.net/ 根据结果获取正确的结构。只需复制选择结果,并生成您的体面结构

或者您可以生成具有 Project 结构数组的新类型:

type Projects []Project

【讨论】:

    【解决方案2】:

    我使用下面这个answer的解决方案使它工作

    我不知道这是一个多么干净的解决方案,但我最终创建了自己的数据类型JSONRaw。 DB 驱动程序将其视为 []btye,但在 Go 代码中仍可将其视为 json.RawMessage

    这是对 encoding/json 库中 MarshalJSONUnmarshalJSON 的复制粘贴重新实现。

    //JSONRaw ...
    type JSONRaw json.RawMessage
    
    //Value ...
    func (j JSONRaw) Value() (driver.Value, error) {
        byteArr := []byte(j)
    
        return driver.Value(byteArr), nil
    }
    
    //Scan ...
    func (j *JSONRaw) Scan(src interface{}) error {
        asBytes, ok := src.([]byte)
        if !ok {
            return error(errors.New("Scan source was not []bytes"))
        }
        err := json.Unmarshal(asBytes, &j)
        if err != nil {
            return error(errors.New("Scan could not unmarshal to []string"))
        }
    
        return nil
    }
    
    //MarshalJSON ...
    func (j *JSONRaw) MarshalJSON() ([]byte, error) {
        return *j, nil
    }
    
    //UnmarshalJSON ...
    func (j *JSONRaw) UnmarshalJSON(data []byte) error {
        if j == nil {
            return errors.New("json.RawMessage: UnmarshalJSON on nil pointer")
        }
        *j = append((*j)[0:0], data...)
        return nil
    }
    
    //Project ....
    type Project struct {
        ID        int64   `db:"project_id, primarykey, autoincrement" json:"id"`
        UserID    int64   `db:"user_id" json:"user_id"`
        Name      string  `db:"name" json:"name"`
        Status    int     `db:"status" json:"status"`
        UpdatedAt int64   `db:"updated_at" json:"updated_at"`
        CreatedAt int64   `db:"created_at" json:"created_at"`
        Apps      JSONRaw `json:"apps"`
    }
    

    但我想知道除此之外是否还有 干净 方法?

    希望这也对其他人有所帮助。

    【讨论】:

    • 嗨,几周前我写了一篇关于处理来自 postgres 的 JSON(B) 的博客。这确实是关于创建自己的类型来处理 JSON。就我而言,我将其转换为 map[string]interface{},我认为 GIN 也会正确处理它。 coussej.github.io/2016/02/16/Handling-JSONB-in-Go-Structs
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-27
    • 1970-01-01
    • 1970-01-01
    • 2014-05-15
    • 1970-01-01
    • 2016-12-27
    相关资源
    最近更新 更多