如何在Golang中正确检索MongoDB中的嵌套对象数组?
解决Golang Mongo驱动解码内容字段时的格式异常问题
你在使用Golang Fiber + Mongo驱动开发博客系统时,定义的Post结构体中Content字段为[]interface{},存入MongoDB的是正常的对象数组,但查询解码后Content变成了嵌套数组加Key/Value键值对的格式——这是因为Mongo驱动对无明确类型的interface{}数组解码时,会将每个对象解析为bson.D(即[]bson.E键值对数组),后续JSON序列化时就呈现出异常格式。
解决方案1:定义明确的内容元素结构体
最可靠的方式是为Content数组中的对象定义具体结构体,让Mongo驱动能精准解析类型:
// 定义Content数组的元素结构体 type ContentItem struct { Data string `json:"data" bson:"data"` } // 修改Post结构体的Content字段类型 type Post struct { ID primitive.ObjectID `json:"_id" bson:"_id,omitempty"` Title *string `json:"title" bson:"title"` Slug *string `json:"slug" bson:"slug"` Content []ContentItem `json:"content" bson:"content,omitempty"` // 替换为明确的结构体数组 CreatedAt time.Time `json:"created_at" bson:"created_at"` UpdatedAt time.Time `json:"updated_at" bson:"updated_at"` PublishedAt *time.Time `json:"published_at" bson:"published_at"` }
修改后,驱动会直接将Mongo中的对象数组解码为[]ContentItem,序列化JSON时就能得到和存储时一致的格式。
解决方案2:使用[]bson.M替代[]interface{}
如果无法提前确定Content元素的结构,需要保留泛型特性,可以将Content字段类型改为[]bson.M(Mongo驱动内置的map类型):
type Post struct { ID primitive.ObjectID `json:"_id" bson:"_id,omitempty"` Title *string `json:"title" bson:"title"` Slug *string `json:"slug" bson:"slug"` Content []bson.M `json:"content" bson:"content,omitempty"` // 替换为[]bson.M CreatedAt time.Time `json:"created_at" bson:"created_at"` UpdatedAt time.Time `json:"updated_at" bson:"updated_at"` PublishedAt *time.Time `json:"published_at" bson:"published_at"` }
bson.M本质是map[string]interface{},驱动解码时会将Mongo中的对象解析为该类型,后续JSON序列化时会正常转换为对象数组,不会出现Key/Value的嵌套格式。
验证修改
修改结构体后,原查询方法无需额外调整,直接调用FindOne解码即可得到正确的Content格式:
func GetPostBySlug(slug string) (Post, error) { post := Post{} filter := bson.M{"slug": slug} database, err := Database.GetMongoDatabase() if err != nil { return post, err } collection := database.Collection(model_name) err = collection.FindOne(ctx, filter).Decode(&post) return post, err }
此时返回的Content字段会和MongoDB中存储的格式一致,为正常的对象数组。
内容的提问来源于stack exchange,提问作者Andrew Rusinas
相关产品推荐
相关产品推荐

