Golang中如何移除JSON输出对象的顶层字段名但保留其属性

Golang中如何移除JSON输出对象的顶层字段名但保留其属性 我正在实现Go API并获取JSON对象作为输出。我得到的输出如下:

{
    "entityId": "5f1",
    "entries": [
        {
            "Fruit": {
                "name": "1cd9",
                "location": "5f1",
                "ID": "7b9",
                "creationDate": "2019-06-26T18:27:10",
                "lastUpdatedDate": "2019-06-26T18:27:28",
                "startDate": "2019-06-26T08:00:00",
                "endDate": "2019-06-26T08:00:00",
                "entryType": 1
            }
        },
        {
           "Fruit": {
                "name": "1c9",
                "location": "51",
                "ID": "79",
                "creationDate": "2019-06-26T18:27:10",
                "lastUpdatedDate": "2019-06-26T18:27:28",
                "startDate": "2019-06-26T08:00:00",
                "endDate": "2019-06-26T08:00:00",
                "entryType": 1
            },
        }]
}

但是,我想要这样的输出:

{
    "entityId": "5f1",
    "entries": [
        {
                "name": "1cd9",
                "location": "5f1",
                "ID": "7b9",
                "creationDate": "2019-06-26T18:27:10",
                "lastUpdatedDate": "2019-06-26T18:27:28",
                "startDate": "2019-06-26T08:00:00",
                "endDate": "2019-06-26T08:00:00",
                "entryType": 1

        },
        {

                "name": "1c9",
                "location": "51",
                "ID": "79",
                "creationDate": "2019-06-26T18:27:10",
                "lastUpdatedDate": "2019-06-26T18:27:28",
                "startDate": "2019-06-26T08:00:00",
                "endDate": "2019-06-26T08:00:00",
                "entryType": 1
          }]
}

我在proto3文件中的数据模型是:

message Entry{
  oneof Type {
   Fruit fruit = 1;
   Animal animals = 2;
   Bird birds = 3;

 }
}  

我尝试在proto中使用oneof类型,并在后端的Go文件中使用嵌套消息来填充模型。MySQL是我的数据库。

var allmt  pb.TypesResponse
for i := 0; i < len(dbEntries); i++ {
mt := &pb.TypesResponse{
            Entries: []*pb.Entry{{
                Type: &pb.Entry_Fruit{
                    dbEntries[i],
                },
            },
            },
        }
   allmt.Entries = append(allmt.Entries, mt.Entries[0])
}

请帮助我实现扁平的JSON对象。


更多关于Golang中如何移除JSON输出对象的顶层字段名但保留其属性的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang中如何移除JSON输出对象的顶层字段名但保留其属性的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go中处理protobuf生成的JSON输出时,可以使用json.RawMessage和自定义JSON序列化来实现移除顶层字段名的需求。以下是解决方案:

package main

import (
	"encoding/json"
	"fmt"
)

// 定义Fruit结构体,使用protobuf标签
type Fruit struct {
	Name           string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
	Location       string `protobuf:"bytes,2,opt,name=location,proto3" json:"location,omitempty"`
	ID             string `protobuf:"bytes,3,opt,name=ID,proto3" json:"ID,omitempty"`
	CreationDate   string `protobuf:"bytes,4,opt,name=creationDate,proto3" json:"creationDate,omitempty"`
	LastUpdatedDate string `protobuf:"bytes,5,opt,name=lastUpdatedDate,proto3" json:"lastUpdatedDate,omitempty"`
	StartDate      string `protobuf:"bytes,6,opt,name=startDate,proto3" json:"startDate,omitempty"`
	EndDate        string `protobuf:"bytes,7,opt,name=endDate,proto3" json:"endDate,omitempty"`
	EntryType      int32  `protobuf:"varint,8,opt,name=entryType,proto3" json:"entryType,omitempty"`
}

// 自定义Entry类型来处理JSON序列化
type Entry struct {
	Type interface{} `json:"-"`
}

// 实现json.Marshaler接口
func (e Entry) MarshalJSON() ([]byte, error) {
	return json.Marshal(e.Type)
}

// 主响应结构体
type TypesResponse struct {
	EntityID string  `protobuf:"bytes,1,opt,name=entityId,proto3" json:"entityId,omitempty"`
	Entries  []Entry `protobuf:"bytes,2,rep,name=entries,proto3" json:"entries,omitempty"`
}

func main() {
	// 模拟从数据库获取的数据
	dbEntries := []Fruit{
		{
			Name:           "1cd9",
			Location:       "5f1",
			ID:             "7b9",
			CreationDate:   "2019-06-26T18:27:10",
			LastUpdatedDate: "2019-06-26T18:27:28",
			StartDate:      "2019-06-26T08:00:00",
			EndDate:        "2019-06-26T08:00:00",
			EntryType:      1,
		},
		{
			Name:           "1c9",
			Location:       "51",
			ID:             "79",
			CreationDate:   "2019-06-26T18:27:10",
			LastUpdatedDate: "2019-06-26T18:27:28",
			StartDate:      "2019-06-26T08:00:00",
			EndDate:        "2019-06-26T08:00:00",
			EntryType:      1,
		},
	}

	// 构建响应
	var allmt TypesResponse
	allmt.EntityID = "5f1"
	
	for i := 0; i < len(dbEntries); i++ {
		entry := Entry{
			Type: dbEntries[i],
		}
		allmt.Entries = append(allmt.Entries, entry)
	}

	// 序列化为JSON
	jsonData, err := json.MarshalIndent(allmt, "", "    ")
	if err != nil {
		panic(err)
	}

	fmt.Println(string(jsonData))
}

如果你需要保持protobuf生成的结构体,可以使用以下方法:

// 使用protobuf生成的结构体时,创建自定义的JSON序列化
type CustomEntry struct {
	*pb.Entry
}

func (ce CustomEntry) MarshalJSON() ([]byte, error) {
	// 根据oneof类型提取具体对象
	switch v := ce.Entry.Type.(type) {
	case *pb.Entry_Fruit:
		return json.Marshal(v.Fruit)
	case *pb.Entry_Animal:
		return json.Marshal(v.Animal)
	case *pb.Entry_Bird:
		return json.Marshal(v.Bird)
	default:
		return json.Marshal(nil)
	}
}

// 在构建响应时使用CustomEntry
var allmt struct {
	EntityID string        `json:"entityId"`
	Entries  []CustomEntry `json:"entries"`
}

allmt.EntityID = "5f1"
for i := 0; i < len(dbEntries); i++ {
	entry := &pb.Entry{
		Type: &pb.Entry_Fruit{
			Fruit: dbEntries[i],
		},
	}
	allmt.Entries = append(allmt.Entries, CustomEntry{Entry: entry})
}

输出结果将是:

{
    "entityId": "5f1",
    "entries": [
        {
            "name": "1cd9",
            "location": "5f1",
            "ID": "7b9",
            "creationDate": "2019-06-26T18:27:10",
            "lastUpdatedDate": "2019-06-26T18:27:28",
            "startDate": "2019-06-26T08:00:00",
            "endDate": "2019-06-26T08:00:00",
            "entryType": 1
        },
        {
            "name": "1c9",
            "location": "51",
            "ID": "79",
            "creationDate": "2019-06-26T18:27:10",
            "lastUpdatedDate": "2019-06-26T18:27:28",
            "startDate": "2019-06-26T08:00:00",
            "endDate": "2019-06-26T08:00:00",
            "entryType": 1
        }
    ]
}

这种方法通过实现自定义的MarshalJSON方法,在序列化时直接输出内部对象的属性,从而移除了顶层的"Fruit"字段名。

回到顶部