为了账号安全,请及时绑定邮箱和手机立即绑定

解组 JSON 保留空值

解组 JSON 保留空值

Go
饮歌长啸 2022-05-05 17:57:07
我的情况如下:我有一个用 Go 制作的服务器/工作者。在后台例程中,服务器接收 JSON 格式的消息,然后使用此数据更新 MongoDB 数据库。问题之一是,某些 MongoDB 数据类型,例如 ObjectId 和 Date,在必须表示为 JSON 时通常会转换为字符串,因此在将该数据插入数据库之前,我将 JSON 解组到一个结构中,并且然后将该结构发送到 MongoDB 驱动程序。该结构实现了 和 等方法UnmarshalJSON,MarshalBSONValue因此保留了它们的数据类型。太好了,一切都解决了。但是通过使用结构我遇到了另一个问题,假设我有以下结构:type Integers struct {    Foo *int `json:"foo" bson:"foo"`    Bar *int `json:"bar" bson:"foo"`    Baz *int `json:"baz" bson:"foo"`}然后我收到以下 JSON:{"foo": 0, "bar": null}有了这个 JSON,我应该用 , 和 ignore 更新我foo = 0的bar = null数据库baz。但是,如果我在我的结构中解组这个 JSON,我将拥有相当于:Integers{    Foo: 1,    Bar: nil,    Baz: nil,}但是有了这个,我无法判断我是否收到了barand baz,或者他们只是默认为nil,所以我无法正确更新数据库。我如何相信它可以解决:通过具有以下结构:type Integers struct {    Foo SmartassInt `json:"foo,omitempty" bson:"foo,omitempty"`    Bar SmartassInt `json:"bar,omitempty" bson:"bar,omitempty"`    Baz SmartassInt `json:"baz,omitempty" bson:"baz,omitempty"`}我将能够区分 anull和未收到的值,如下例所示:var foo int = 0var fooPointer *int = &foovar barPointer *int = nilintegers := Integers{    Foo: &fooPointer,    Bar: &barPointer,    Baz: nil,}使用这种结构,baz不会被插入到数据库中,因为它的值是nil,并且nil由于 flag 被忽略omitempty。bar然而不是nil,但它指向nil,这与为空不同,因此它像null在数据库中一样正确插入。但是我怎样才能用收到的 JSON 来实现这个初始化呢?标准 JSON 解组器会将bar和都初始化baz为nil.实现我自己的编组器方法,例如type NullableInt **intfunc (i NullableInt) MarshalJSON() ([]byte, error) {}func (i NullableInt) UnmarshalJSON(data []byte) error {}也不可能,因为NullableInt是指针,我无法在指针上实现方法。那么,我可以使用哪种方法来解决这个问题?
查看完整描述

1 回答

?
凤凰求蛊

TA贡献1825条经验 获得超4个赞

在解码方面,您可以为自定义类型编写自定义解组器:


type MaybeInt struct {

    Present bool

    Null    bool

    Value   int64

}


func (m *MaybeInt) UnmarshalJSON(data []byte) error {

    s := string(data)

    m.Present = true

    if s == "null" {

        m.Null = true

        return nil

    }

    v, err := strconv.ParseInt(s, 10, 64)

    m.Value = v

    return err

}

完整的例子在这里。不幸的是,这在编码方面不起作用:MarshalJSON处理程序无法指示该字段为空。显而易见的方法是nil, nil从 Marshaler 返回,但这不起作用。也不回[]byte{}, nil。


你可能会想:好吧,让我们使用一个指针,并将它设置为nil当我们想说该字段应该被省略时。这适用于解码端,但现在编码端失败了,因为编码器看到文字null并且根本不调用我们的编码器!


最终,我们可以将这两种技术结合起来:读入MaybeInt、编码(写入)*MaybeInt。我们需要并行结构类型。我们可以根据输入类型设置输出类型。我不认为这很漂亮,而且其中的reflect代码很糟糕(你也可以看到我所有的调试痕迹),但这实际上似乎有效:Playground link。在实践中reflect,您可能只为每个“可能”值的情况编写一个函数,而不是使用 。


查看完整回答
反对 回复 2022-05-05
  • 1 回答
  • 0 关注
  • 155 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信