将Golang JSON存储到Postgresql中

16

我想将一个包含JSON字段的结构体存储到我的数据库中。

type Comp struct {
    CompId               int64           `db:"comp_id" json:"comp_id"`
    StartDate            time.Time       `db:"start_date" json:"start_date"`
    EndDate              time.Time       `db:"end_date" json:"end_date"`
    WeeklySchedule       json.RawMessage `db:"weekly_schedule" json:"weekly_schedule"`
}

这个表的模式是:

CREATE TABLE IF NOT EXISTS Tr.Comp(
    comp_id                 SERIAL,
    start_date              timestamp NOT NULL,
    end_date                timestamp NOT NULL,
    weekly_schedule         json NOT NULL,
    PRIMARY KEY (comp_id)
);

我在我的项目中使用了sqlx和lib/pq驱动程序,但是以下内容无法执行。相反,它会发生panic错误,指出存在空指针。DB是一个全局 *sqlx.DB 结构体。
    tx := DB.MustBegin()

    compFixture := Comp{
        StartDate:            time.Now(),
        EndDate:              time.Now().AddDate(1, 0, 0),
        WeeklySchedule:       json.RawMessage([]byte("{}")),
    }
    _, err = tx.NamedExec(
        `INSERT INTO 
            Tr.Comp(comp_id, 
                start_date, end_date, weekly_schedule) 
            VALUES (DEFAULT, 
                :start_date, :end_date, :weekly_schedule)  
            RETURNING comp_id;`, compFixture)
    if err != nil {
        t.Fatal("Error creating fixture.", err)
    }

当我从模式(schema)和固定装置(fixture)中移除weekly_schedule时,一切运行正常。但是当这个字段被包含时,程序会出现恐慌(panic)。有没有想法如何在我的数据库模式和Go结构体中定义weekly_schedule字段?

3个回答

15

sqlx在github.com/jmoiron/sqlx/types中有一个类型为JSONText的数据类型,可实现您所需功能。

JSONText文档


是的,这正是我正在寻找的。谢谢。 - moesef
最近更名为JSONText,请参见https://github.com/jmoiron/sqlx/commit/4301d72cf9192e9d0a830370e31323dce943e005 - Harry Moreno
@HarryMoreno 我更新了我的答案。谢谢你让我知道。 - jmaloney
嗨,我编辑了答案并放了一个结构体的例子,因为有些人如果没有代码示例就不会仔细阅读答案,但这对我很有帮助,谢谢。 - André Betiolo

6

我不知道这是否是一个完美有效的解决方案,但我最终创建了自己的数据类型JSONRaw。DB驱动将它视为[]byte,但在Go代码中仍可像json.RawMessage一样处理。

type JSONRaw json.RawMessage

func (j JSONRaw) Value() (driver.Value, error) {
    byteArr := []byte(j)

    return driver.Value(byteArr), nil
}

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
}

func (m *JSONRaw) MarshalJSON() ([]byte, error) {
    return *m, nil
}

func (m *JSONRaw) UnmarshalJSON(data []byte) error {
    if m == nil {
        return errors.New("json.RawMessage: UnmarshalJSON on nil pointer")
    }
    *m = append((*m)[0:0], data...)
    return nil
}

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

0

来自 Go 文档:

json.RawMessage is a raw encoded JSON object. It implements Marshaler and Unmarshaler and can be used to delay JSON decoding or precompute a JSON encoding.

如果您在 package json 的 json.RawMessage 提供的示例中使用 log.Printf("%#", colors),您会发现在取消编组 json 对象后,“Point”成员未被取消编组,而是以 []byte 格式保留,直到颜色格式被修复并显式取消编组“Point”。

您是否尝试过在将 WeeklySchedule 取消编组并放入数据库之前进行取消编组?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接