如何在 go 中展平嵌套的 json 结构
How to flatten out a nested json structure in go
我正在从 mongo 获取嵌套数据,我想将其展平到结构中以将其存储在 csv 文件中。
数据如下所示:
{
"_id" : "bec7bfaa-7a47-4f61-a463-5966a2b5c8ce",
"data" : {
"driver" : {
"etaToStore" : 156
},
"createdAt" : 1532590052,
"_id" : "07703a33-a3c3-4ad5-9e06-d05063474d8c"
}
}
而我最终想要得到的结构应该是这样的
type EventStruct struct {
Id string `bson:"_id"`
DataId string `bson:"data._id"`
EtaToStore string `bson:"data.driver.etaToStore"`
CreatedAt int `bson:"data.createdAt"`
}
这行不通,所以按照some SO answers我把它分解成多个结构:
// Creating a structure for the inner struct that I will receive from the query
type DriverStruct struct {
EtaToStore int `bson:"etaToStore"`
}
type DataStruct struct {
Id string `bson:"_id"`
Driver DriverStruct `bson:"driver"`
CreatedAt int `bson:"createdAt"`
}
// Flattenning out the structure & getting the fields we need only
type EventStruct struct {
Id string `bson:"_id"`
Data DataStruct `bson:"data"`
}
这从 Mongo 查询结果中获取所有数据,但它是嵌套的:
{
"Id": "bec7bfaa-7a47-4f61-a463-5966a2b5c8ce",
"Data": {
"Id": a33-a3c3-4ad5-9e06-d05063474d8c,
"Driver": {
"EtaToStore": 156
},
"CreatedAt": 1532590052
}
}
我想要结束的是:
{
"Id": "bec7bfaa-7a47-4f61-a463-5966a2b5c8ce",
"DataId": "a33-a3c3-4ad5-9e06-d05063474d8c",
"EtaToStore": 156,
"CreatedAt": 1532590052
}
我确定有一个简单的方法可以做到这一点,但我想不通,求助!
您可以使用与以下基本相同的逻辑:
package utils
// FlattenIntegers flattens nested slices of integers
func FlattenIntegers(slice []interface{}) []int {
var flat []int
for _, element := range slice {
switch element.(type) {
case []interface{}:
flat = append(flat, FlattenIntegers(element.([]interface{}))...)
case []int:
flat = append(flat, element.([]int)...)
case int:
flat = append(flat, element.(int))
}
}
return flat
}
(来源:https://gist.github.com/Ullaakut/cb1305ede48f2391090d57cde355074f)
根据您 JSON 中的内容对其进行调整。如果您希望它是通用的,那么您需要支持它可以包含的所有类型。
您可以实现 json.Unmarshaler
接口来添加自定义方法来解组 json。然后在该方法中,您可以使用嵌套结构格式,但 return 最后是扁平化格式。
func (es *EventStruct) UnmarshalJSON(data []byte) error {
// define private models for the data format
type driverInner struct {
EtaToStore int `bson:"etaToStore"`
}
type dataInner struct {
ID string `bson:"_id" json:"_id"`
Driver driverInner `bson:"driver"`
CreatedAt int `bson:"createdAt"`
}
type nestedEvent struct {
ID string `bson:"_id"`
Data dataInner `bson:"data"`
}
var ne nestedEvent
if err := json.Unmarshal(data, &ne); err != nil {
return err
}
// create the struct in desired format
tmp := &EventStruct{
ID: ne.ID,
DataID: ne.Data.ID,
EtaToStore: ne.Data.Driver.EtaToStore,
CreatedAt: ne.Data.CreatedAt,
}
// reassign the method receiver pointer
// to store the values in the struct
*es = *tmp
return nil
}
这个问题已经有一年半了,但我今天 运行 在对 API 更新做出反应时进入了这个问题,这让我处于同样的境地,所以这是我的解决方案(其中,不可否认,我没有用 bson
进行测试,但我假设 json
和 bson
字段标记 reader 实现以相同的方式处理它们)
嵌入式(有时称为匿名)字段可以捕获 JSON,因此您可以将多个结构组合成一个复合结构,其行为类似于单个结构。
{
"_id" : "bec7bfaa-7a47-4f61-a463-5966a2b5c8ce",
"data" : {
"driver" : {
"etaToStore" : 156
},
"createdAt" : 1532590052,
"_id" : "07703a33-a3c3-4ad5-9e06-d05063474d8c"
}
}
type DriverStruct struct {
EtaToStore string `bson:"etaToStore"`
type DataStruct struct {
DriverStruct `bson:"driver"`
DataId string `bson:"_id"`
CreatedAt int `bson:"createdAt"`
}
type EventStruct struct {
DataStruct `bson:"data"`
Id string `bson:"_id"`
}
您可以访问嵌入式结构的嵌套字段,就像父结构包含等效字段一样,例如EventStructInstance.EtaToStore
是获取它们的有效方法。
好处:
- 您不必实现
Marshaller
或 Unmarshaller
接口,这对于这个问题来说有点矫枉过正
- 不需要在中间结构之间复制任何字段
- 免费处理编组和解组
我正在从 mongo 获取嵌套数据,我想将其展平到结构中以将其存储在 csv 文件中。
数据如下所示:
{
"_id" : "bec7bfaa-7a47-4f61-a463-5966a2b5c8ce",
"data" : {
"driver" : {
"etaToStore" : 156
},
"createdAt" : 1532590052,
"_id" : "07703a33-a3c3-4ad5-9e06-d05063474d8c"
}
}
而我最终想要得到的结构应该是这样的
type EventStruct struct {
Id string `bson:"_id"`
DataId string `bson:"data._id"`
EtaToStore string `bson:"data.driver.etaToStore"`
CreatedAt int `bson:"data.createdAt"`
}
这行不通,所以按照some SO answers我把它分解成多个结构:
// Creating a structure for the inner struct that I will receive from the query
type DriverStruct struct {
EtaToStore int `bson:"etaToStore"`
}
type DataStruct struct {
Id string `bson:"_id"`
Driver DriverStruct `bson:"driver"`
CreatedAt int `bson:"createdAt"`
}
// Flattenning out the structure & getting the fields we need only
type EventStruct struct {
Id string `bson:"_id"`
Data DataStruct `bson:"data"`
}
这从 Mongo 查询结果中获取所有数据,但它是嵌套的:
{
"Id": "bec7bfaa-7a47-4f61-a463-5966a2b5c8ce",
"Data": {
"Id": a33-a3c3-4ad5-9e06-d05063474d8c,
"Driver": {
"EtaToStore": 156
},
"CreatedAt": 1532590052
}
}
我想要结束的是:
{
"Id": "bec7bfaa-7a47-4f61-a463-5966a2b5c8ce",
"DataId": "a33-a3c3-4ad5-9e06-d05063474d8c",
"EtaToStore": 156,
"CreatedAt": 1532590052
}
我确定有一个简单的方法可以做到这一点,但我想不通,求助!
您可以使用与以下基本相同的逻辑:
package utils
// FlattenIntegers flattens nested slices of integers
func FlattenIntegers(slice []interface{}) []int {
var flat []int
for _, element := range slice {
switch element.(type) {
case []interface{}:
flat = append(flat, FlattenIntegers(element.([]interface{}))...)
case []int:
flat = append(flat, element.([]int)...)
case int:
flat = append(flat, element.(int))
}
}
return flat
}
(来源:https://gist.github.com/Ullaakut/cb1305ede48f2391090d57cde355074f)
根据您 JSON 中的内容对其进行调整。如果您希望它是通用的,那么您需要支持它可以包含的所有类型。
您可以实现 json.Unmarshaler
接口来添加自定义方法来解组 json。然后在该方法中,您可以使用嵌套结构格式,但 return 最后是扁平化格式。
func (es *EventStruct) UnmarshalJSON(data []byte) error {
// define private models for the data format
type driverInner struct {
EtaToStore int `bson:"etaToStore"`
}
type dataInner struct {
ID string `bson:"_id" json:"_id"`
Driver driverInner `bson:"driver"`
CreatedAt int `bson:"createdAt"`
}
type nestedEvent struct {
ID string `bson:"_id"`
Data dataInner `bson:"data"`
}
var ne nestedEvent
if err := json.Unmarshal(data, &ne); err != nil {
return err
}
// create the struct in desired format
tmp := &EventStruct{
ID: ne.ID,
DataID: ne.Data.ID,
EtaToStore: ne.Data.Driver.EtaToStore,
CreatedAt: ne.Data.CreatedAt,
}
// reassign the method receiver pointer
// to store the values in the struct
*es = *tmp
return nil
}
这个问题已经有一年半了,但我今天 运行 在对 API 更新做出反应时进入了这个问题,这让我处于同样的境地,所以这是我的解决方案(其中,不可否认,我没有用 bson
进行测试,但我假设 json
和 bson
字段标记 reader 实现以相同的方式处理它们)
嵌入式(有时称为匿名)字段可以捕获 JSON,因此您可以将多个结构组合成一个复合结构,其行为类似于单个结构。
{
"_id" : "bec7bfaa-7a47-4f61-a463-5966a2b5c8ce",
"data" : {
"driver" : {
"etaToStore" : 156
},
"createdAt" : 1532590052,
"_id" : "07703a33-a3c3-4ad5-9e06-d05063474d8c"
}
}
type DriverStruct struct {
EtaToStore string `bson:"etaToStore"`
type DataStruct struct {
DriverStruct `bson:"driver"`
DataId string `bson:"_id"`
CreatedAt int `bson:"createdAt"`
}
type EventStruct struct {
DataStruct `bson:"data"`
Id string `bson:"_id"`
}
您可以访问嵌入式结构的嵌套字段,就像父结构包含等效字段一样,例如EventStructInstance.EtaToStore
是获取它们的有效方法。
好处:
- 您不必实现
Marshaller
或Unmarshaller
接口,这对于这个问题来说有点矫枉过正 - 不需要在中间结构之间复制任何字段
- 免费处理编组和解组