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

9 回复

@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"`
}
回到顶部