将嵌套的MongoDB文档数组解码为Go中的结构体切片的最快方法是什么?

huangapple go评论77阅读模式
英文:

What is the fastest way to decode a nested MongoDB document array into a struct slice in Go?

问题

这是我的问题。我正在使用gqlgen库运行一个GraphQL服务器。在我的数据库中,我有一个类似于这样的MongoDB文档:

{
  "_id": ObjectID(...),
  "somefield": "data",
  "anArrayOfObjects": [
    {
      "field1": "value1",
      "field2": "value2"
    },
    ...
  ]
}

我想要的是只解码字段anArrayOfObjects为一个切片(可能看起来像[]MyObj,其中MyObj是一个结构体)。

(为了一点背景,我只想要这个字段,因为数组非常大,并且它有自己的GraphQL解析器)。

这是我目前尝试过的:

ObjectID, err := primitive.ObjectIDFromHex("someid")
// 进行一些错误检查

opts := options.FindOne().SetProjection(
    bson.D{{Key: "anArrayOfObjects", Value: 1}, {Key: "_id", Value: 0}},
)
myslice = []MyObj{}
err := coll.FindOne(ctx, bson.M{"_id": ObjectID}, opts).Decode(&myslice)
// 错误为"无法将文档解码为[]MyObj"

如果我运行

result = primitive.D{} // 或 primitive.M{}
err := coll.FindOne(ctx, bson.M{"_id": ObjectID}, opts).Decode(&result)
// 错误为nil,result包含了我想要的一切,但不是在"理想"的数据结构中

通过后者,我可以遍历result然后将所有内容映射到每个结构字段(类似于这个答案)。但我的直觉告诉我,可能有比这更好的方法。

提前感谢!

英文:

Here's my problem. I'm using gqlgen library to run a GraphQL server. In my database I have a MongoDB document that looks like this:

{
  "_id": ObjectID(...),
  "somefield": "data",
  "anArrayOfObjects": [
    {
      "field1": "value1",
      "field2": "value2
    },
    ...
  ]
}

What I want is to be able to only decode the field anArrayOfObjects into a slice (may look like []MyObj, where MyObj is a struct).

(For a little context, I only want this field because the array is quite large and it has it's own GraphQL resolver).

Here's currently what I have tried:

ObjectID, err := primitive.ObjectIDFromHex("someid")
// do some error check

opts := options.FindOne().SetProjection(
    bson.D{{Key: "anArrayOfObjects", Value: 1}, {Key: "_id", Value: 0}},
)
myslice = []MyObj{}
err := coll.FindOne(ctx, bson.M{"_id": ObjectID}, opts).Decode(&myslice)
// err is "cannot decode document into []MyObj"

If instead I run

result = primitive.D{} // or primitive.M{}
err := coll.FindOne(ctx, bson.M{"_id": ObjectID}, opts).Decode(&result)
// err is nil and result contains everything I want but not in the "ideal" data structure

Doing the latter, I reckon I can iterate through result and then map everything to every struct field (similar to this answer). But my intuition is that probably there is a better way to do this than that.

Thanks in advance!

答案1

得分: 0

您的查询结果将是一个包含anArrayOfObjects字段下数组的文档,而不仅仅是该字段的数组值。而且您不能将文档解码为Go切片,这就是错误消息告诉您的内容。

因此,您需要将其解组为具有该字段的结构体:

var result struct{
    MySlice []MyObj `bson:"anArrayOfObjects"`
}
err := coll.FindOne(ctx, bson.M{"_id": ObjectID}, opts).Decode(&result)

来自MongoDB的数组将是result.MySlice

英文:

The result of your query will be a document holding the array under the anArrayOfObjects field, and not the array value of that field alone. And you can't decode a document into a Go slice, that's what the error message tells you.

So unmarshal into a struct having that field:

var result struct{
    MySlice []MyObj `bson:"anArrayOfObjects"`
}
err := coll.FindOne(ctx, bson.M{"_id": ObjectID}, opts).Decode(&result)

The array from MongoDB will be result.MySlice.

huangapple
  • 本文由 发表于 2022年11月7日 16:11:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/74343616.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定