Вложенный результат JSON в Golang от Postgres

Я использую джин и gorp

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

Результаты:  введите описание изображения здесь

Голанг

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: Я новичок в Голанге


person Omar Massad    schedule 17.03.2016    source источник
comment
Все методы json.RawMessage принимают получатель указателя. Вы пробовали добавить Apps *json.RawMessage ...?   -  person molivier    schedule 17.03.2016


Ответы (2)


вы можете использовать этот сайт http://json2struct.mervine.net/, чтобы получить правильную структуру в соответствии с результатом. просто скопируйте результат выбора и сгенерируйте свою достойную структуру

или вы можете создать новый тип, который имеет массив структур проекта:

type Projects []Project
person ugurozgen    schedule 17.03.2016

Я заставил его работать, используя это решение ниже из этого ответа

Я не знаю, насколько это чистое решение, но в итоге я создал свой собственный тип данных JSONRaw. Драйвер БД видит его как []btye, но его можно рассматривать как json.RawMessage в коде перехода.

Это повторная реализация копипаста MarshalJSON и UnmarshalJSON из библиотеки encoding / json.

//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"`
}

введите описание изображения здесь

Но мне было интересно, есть ли чистый способ, отличный от этого?

Надеюсь, это также поможет другим.

person Omar Massad    schedule 17.03.2016
comment
Привет, несколько недель назад я написал блог о работе с JSON (B), поступающим из postgres. Это действительно о создании вашего собственного типа для обработки JSON. В моем случае я преобразовал его в интерфейс map [string] {}, который, как я полагаю, также будет правильно обрабатываться GIN. coussej.github.io/2016/02/16 / Handling-JSONB-in-Go-Structs - person coussej; 17.03.2016