Golang解码错误 - 嵌套结构体的处理
Golang解码错误 - 嵌套结构体的处理 你好
我是Golang和GraphQL的新手。在将游标解码到结构体以处理GraphQL查询时遇到了错误。任何帮助都将不胜感激。
谢谢
错误: ------- *无法将文档解码为 []model.Level1 退出状态 1
这是我的GraphQL模式
type SalesOrder {
Id: String
Name: String
Level1: [Level1]
}
type Level1 {
Lname: String
Level2: [Level2]
}
type Level2 {
Lname: String
Level3: [Level3]
}
type Level3 {
Lname: String
Level3: [Level3]
}
type Query {
salesorders: [SalesOrder!]!
}
input NewSalesOrder {
text: String!
userId: String!
}
type Mutation {
CreateSalesOrder(input: NewSalesOrder!): SalesOrder!
}
//来自MongoDB的文档
{"Id":"12345","Name":"Test","Level1":{"Lname":"First level","Level2":{"Lname":"Secondlevel","Level3":{"Lname":"Third level"}}},"_id":{"$oid":"5e8ef1fb9ce752aac5d18c52"}}
//解析器中用于解码到Golang结构体的代码
ctx, _ = context.WithTimeout(context.Background(), 30*time.Second)
cursor, err := collection.Find(ctx, bson.D{})
if err != nil {
log.Fatal(err)
}
for cursor.Next(context.TODO()) {
var salesOrder model.SalesOrder
err := cursor.Decode(&salesOrder)
if err != nil {
log.Fatal(err)
}
salesOrderArr = append(salesOrderArr, &salesOrder)
}
if err := cursor.Err(); err != nil {
log.Fatal(err)
}
cursor.Close(context.TODO())
//-------------
//golang结构体
// 由 github.com/99designs/gqlgen 生成,请勿编辑。
package model
type Level1 struct {
Lname *string `json:"Lname"`
Level2 []*Level2 `json:"Level2"`
}
type Level2 struct {
Lname *string `json:"Lname"`
Level3 []*Level3 `json:"Level3"`
}
type Level3 struct {
Lname *string `json:"Lname"`
Level3 []*Level3 `json:"Level3"`
}
type NewSalesOrder struct {
Text string `json:"text"`
UserID string `json:"userId"`
}
type SalesOrder struct {
ID *string `json:"Id"`
Name *string `json:"Name"`
Level1 []*Level1 `json:"Level1"`
}
更多关于Golang解码错误 - 嵌套结构体的处理的实战教程也可以访问 https://www.itying.com/category-94-b0.html
@skillian。感谢指出。已更新。
更多关于Golang解码错误 - 嵌套结构体的处理的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
@skillian。谢谢。也添加了Go结构体。它是一个可选数组,所以我的理解是它应该接受一个或多个。
JSON 包含这个数组 [],但是当它被插入到 MongoDB 时,MongoDB 将其存储为数组对象。现在解码该对象时出现了这个错误。
rajagopalss:
@rajagopalss 请尝试使用三个反引号(即 ```)而不是撇号,然后重新粘贴你的代码,这样我们就能更容易地阅读并为你提供答案。
@skillian,我之前为了测试目的,将XML转换为JSON然后上传到MongoDB。现在我使用了另一个转换器来将XML转换为JSON。看起来我之前使用的转换器没有添加[]。你之前的评论帮助我发现了这个问题。非常感谢。
@rajagopalss,我刚用谷歌搜索了GraphQL,发现 [Level1] 表示期望的是一个 Level1 对象数组,但你提供的JSON里只有一个 Level1 对象,而不是一个数组。嵌套的层级也存在同样的问题。
谢谢你,@rajagopalss。我看到了 GraphQL 模式定义,但我们能否也看一下 Go 结构体的定义呢?
它应该适用于一个(或零个)或多个元素,但它仍然必须是一个数组。我认为这会奏效:
{
"Id": "12345",
"Name": "Test",
"Level1": [{
"Lname": "First level",
"Level2": [{
"Lname": "Secondlevel",
"Level3": [{
"Lname": "Third level"
}]
}]
}],
"_id": {
"$oid": "5e8ef1fb9ce752aac5d18c52"
}
}
问题在于你的MongoDB文档结构与Go结构体定义不匹配。文档中的嵌套字段是对象,但结构体定义的是切片。
MongoDB文档:
{
"Level1": {
"Lname": "First level",
"Level2": {
"Lname": "Secondlevel",
"Level3": {
"Lname": "Third level"
}
}
}
}
Go结构体:
type SalesOrder struct {
Level1 []*Level1 `json:"Level1"` // 期望数组,但文档中是对象
}
解决方案:
修改你的Go结构体定义,将切片改为指针:
// 修改后的结构体
package model
type Level1 struct {
Lname *string `json:"Lname"`
Level2 *Level2 `json:"Level2"` // 改为指针,不是切片
}
type Level2 struct {
Lname *string `json:"Lname"`
Level3 *Level3 `json:"Level3"` // 改为指针,不是切片
}
type Level3 struct {
Lname *string `json:"Lname"`
Level3 *Level3 `json:"Level3"` // 改为指针,不是切片
}
type SalesOrder struct {
ID *string `json:"Id"`
Name *string `json:"Name"`
Level1 *Level1 `json:"Level1"` // 改为指针,不是切片
}
如果你的GraphQL模式需要数组,但MongoDB存储的是单个对象,你需要调整数据存储方式或添加转换逻辑:
// 如果需要保持GraphQL的数组类型,可以添加转换方法
func (so *SalesOrder) ToGraphQL() *SalesOrder {
if so.Level1 == nil {
return so
}
// 将单个Level1对象转换为切片
return &SalesOrder{
ID: so.ID,
Name: so.Name,
Level1: []*Level1{so.Level1},
}
}
或者在解码后手动转换:
for cursor.Next(context.TODO()) {
var tempOrder struct {
ID *string `bson:"Id"`
Name *string `bson:"Name"`
Level1 *Level1 `bson:"Level1"`
}
err := cursor.Decode(&tempOrder)
if err != nil {
log.Fatal(err)
}
// 转换为GraphQL期望的结构
salesOrder := &model.SalesOrder{
ID: tempOrder.ID,
Name: tempOrder.Name,
Level1: []*model.Level1{tempOrder.Level1},
}
salesOrderArr = append(salesOrderArr, salesOrder)
}
确保你的MongoDB文档结构与Go结构体完全匹配,或者使用bson标签指定不同的映射关系:
type SalesOrder struct {
ID *string `bson:"Id" json:"Id"`
Name *string `bson:"Name" json:"Name"`
Level1 []*Level1 `bson:"Level1" json:"Level1"`
}

