英文:
Storing Golang JSON into Postgresql
问题
我想将一个包含 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)
}
当我从模式和 fixture 中移除 weekly_schedule
字段时,一切都可以正常运行。但是出现问题的原因是,当包含该字段时,程序会发生 panic。你有什么想法,我应该如何在数据库模式和 Go 结构体中定义 weekly_schedule
字段?
英文:
I want to store a certain struct into my database that has a JSON field within it.
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"`
}
The schema for the table is:
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)
);
I am using sqlx and lib/pq driver in my project and the following will not execute. Instead it panics saying there is a nil pointer. DB is a global *sqlx.DB
struct
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)
}
When I remove weekly_schedule
from the schema and fixture things run fine. But for some reason, the when this field is included, the program panics. Any idea as to how I should define the weekly_schedule
field in both my DB schema and Go struct?
答案1
得分: 15
sqlx在github.com/jmoiron/sqlx/types
中有一个名为JSONText
的类型,它可以满足你的需求。
doc 关于 JSONText 的文档。
英文:
sqlx has a type JSONText
in github.com/jmoiron/sqlx/types
that will do what you need
doc for JSONText
答案2
得分: 5
我不知道这个解决方案有多干净,但我最终创建了自己的数据类型JSONRaw
。数据库驱动程序将其视为[]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 errors.New("Scan source was not []bytes")
}
err := json.Unmarshal(asBytes, &j)
if err != nil {
return 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
库中复制粘贴重新实现的MarshalJSON
和UnmarshalJSON
函数。
英文:
I don't know how clean of a solution this is but I ended up making my own data type JSONRaw
. The DB driver sees it as a []btye
but it can still be treated like a json.RawMessage in the Go Code.
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
}
This is copy paste reimplementation of MarshalJSON
and UnmarshalJSON
from the encoding/json
library.
答案3
得分: 0
根据Go文档:
json.RawMessage是一个原始编码的JSON对象。它实现了Marshaler和Unmarshaler接口,可以用于延迟JSON解码或预先计算JSON编码。
如果在提供的示例中使用log.Printf("%#", colors),你会发现在解码JSON对象后,'Point'成员没有被解码,而是以[]byte格式保留,直到颜色格式被修复并且'Point'被显式解码。
你是否尝试过在将WeeklySchedule解码并放入数据库之前进行解码操作?
英文:
from the go documentation:
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.
if you log.Printf("%#", colors) in the example provided at package json json.RawMessage you can see that after unmarshalling the json object 'Point'-member isn't unmarshalled but left in []byte format until the color-format is fixed and 'Point' is unmarshalled explicitly.
Did you try something like unmarshal WeeklySchedule before putting it into the DB?
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论