【发布时间】:2015-08-14 22:28:13
【问题描述】:
我使用键值存储作为我的 golang 应用程序的后端,日期作为键(以保持条目排序),json 文档作为值。我存储的每个 json 文档中都存在 json (foo) 和 type 和 date 的顶级命名空间,但在其他方面存在一些差异(尤其是对于一些嵌套的 json 数据),所以当我从数据库中提取 key 时,我真的不知道我在循环时要提取什么。这是json数据的示例
{
"foo": {
"id": "124",
"type": "baz",
"rawdata": [
123,
345,
345
],
"epoch": "1433120656704"
}
}
{
"foo": {
"id": "234",
"type": "bar",
"rawdata": [
{
"key": "dog",
"values": [
123,
234
]
},
{
"key": "cat",
"values": [
23,
45
]
}
],
"epoch": "1433120656705"
}
}
当我从数据库中提取数据时,我要做的第一件事是将每个条目解组到 map[string]*json.RawMessage 以处理 foo 命名空间
//as I'm looping through the entries in the database
var objmap map[string]*json.RawMessage
if err := json.Unmarshal(dbvalue, &objmap); err !=nil{
return err
}
但是,与那个 SO 答案不同,当我必须再次解组 foo 命名空间下包含的任何内容时,我不知道要解组到哪个结构
if err :=json.Unmarshal(*objmap["foo"], &bazorbar; err != nil{
return err
}
type Baz struct{
Id string `json:"id"`
Type string `json:"type"`
RawData []int `json:"rawdata"`
Epoch string `json:"epoch"`
}
type Bar struct{
Id string `json:"id"`
Type string `json:"type"`
RawData []*Qux `json:"rawdata"`
Epoch string `json:"epoch"`
}
//nested inside Bar
type Qux struct{
Key string `json:"key"`
Values []int `json:"values`
}
两部分问题:
- 有没有办法避免重复解组(或者这是我什至不应该关心的事情)
- 如何确定将 json.RawMessage 解组到哪个结构(也允许嵌套 json 数据)
更新:@chendesheng 提供的初始答案使我能够找出类型,但一旦确定类型(我需要这样做)就不会再次解组到结构中,因此基于在 cmets 对他/她的回答进行对话时,我会对这些可能性中的任何一种都感兴趣
a) 复制 json.RawMessage,按照您显示的方式解组到接口中(通过 chendesheng 的回答),然后在知道类型后解组该结构的副本(从解组到接口中)?
b) 使用正则表达式来确定类型,然后在知道该类型后将其解组为该类型的结构
【问题讨论】:
-
无意冒犯,但我认为你应该重新考虑你的设计,因为你应该能够避免在运行时做出这样的决定,或者至少使用某种类型标志来避免这种更松散的内省决定如何反序列化的方法。您将您的数据库中的数据视为来自某些无法控制和不可预测的第三方,我不建议这样做。
-
@evanmcdonnal 感谢您的意见。我会考虑到这一点,如果我找到更好的方法来做到这一点,我会的,但是,我不相信我将 t 视为来自不可预测的第三方。只是 json 文档的结构不一样,因此必须解组为不同的结构,因此在选择要解组的结构之前,我必须弄清楚 json 的样子
-
是的,json 代表不同的类型。您也可以将类型信息存储在数据库中,并使用它对调用 Unmarshal 之前的类型做出 100% 的决定性决定,您使用 unmarshal 就像它是 try/catch 一样,而不是使用 type info + select to解组为正确的类型,没有不确定的运行时行为。
标签: json go unmarshalling