解组 JSON 保留空值

我的情况如下:


我有一个用 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 = 0

var fooPointer *int = &foo

var barPointer *int = nil


integers := Integers{

    Foo: &fooPointer,

    Bar: &barPointer,

    Baz: nil,

}

使用这种结构,baz不会被插入到数据库中,因为它的值是nil,并且nil由于 flag 被忽略omitempty。bar然而不是nil,但它指向nil,这与为空不同,因此它像null在数据库中一样正确插入。


但是我怎样才能用收到的 JSON 来实现这个初始化呢?


标准 JSON 解组器会将bar和都初始化baz为nil.


实现我自己的编组器方法,例如


type NullableInt **int


func (i NullableInt) MarshalJSON() ([]byte, error) {


}


func (i NullableInt) UnmarshalJSON(data []byte) error {


}

也不可能,因为NullableInt是指针,我无法在指针上实现方法。


那么,我可以使用哪种方法来解决这个问题?


饮歌长啸
浏览 156回答 1
1回答

凤凰求蛊

在解码方面,您可以为自定义类型编写自定义解组器: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,您可能只为每个“可能”值的情况编写一个函数,而不是使用 。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go