
mgo 默认将 Go 结构体的导出字段名转为小写作为 MongoDB 字段名,导致查询失败;需使用 bson 结构体标签显式指定字段名以保持大小写一致。
mgo 默认将 go 结构体的导出字段名转为小写作为 mongodb 字段名,导致查询失败;需使用 `bson` 结构体标签显式指定字段名以保持大小写一致。
在使用 mgo(v2)操作 MongoDB 时,一个常见且易被忽视的行为是:结构体字段名在序列化为 BSON 文档插入数据库时,默认会被自动转换为小写形式。这并非 MongoDB 本身的限制,而是 mgo(基于其底层 bson 包)的默认编码规则所致。
根据 mgo/bson.Marshal 文档说明:
“The lowercased field name is used as the key for each exported field, but this behavior may be changed using the respective field tag.”
即:所有导出字段(首字母大写的字段)默认以小写形式作为 BSON 键名;但可通过 bson struct tag 显式覆盖该行为。
在你的示例中:
type Record struct {
Dimension_id int
Attribute string
Hour string
Frequency_count int
}
尽管字段名为 Dimension_id、Attribute 等,mgo 在插入时会将其转为 "dimension_id"、"attribute"、"hour"、"frequency_count" —— 这正是你在 MongoDB shell 中观察到的结果:
{ "_id" : ObjectId("..."), "dimension_id" : 2, "attribute" : "good", "hour" : "20160712_06", "frequency_count" : 100 }
因此,后续用 bson.M{"Dimension_id": 2} 查询必然失败(键不存在),而 bson.M{"dimension_id": 2} 才能匹配。
✅ 正确做法:使用 bson 标签显式声明字段名
type Record struct {
Dimension_id int `bson:"Dimension_id"`
Attribute string `bson:"Attribute"`
Hour string `bson:"Hour"`
Frequency_count int `bson:"Frequency_count"`
}
添加上述标签后,mgo 将严格按标签值(而非默认小写规则)序列化字段,插入文档将保留原始大小写:
{ "_id": ..., "Dimension_id": 2, "Attribute": "good", "Hour": "20160712_06", "Frequency_count": 100 }
此时,以下查询即可正常工作:
err = c.Find(bson.M{"Dimension_id": 2, "Attribute": "good", "Hour": "20160712_06"}).One(&result)
⚠️ 注意事项:
- bson 标签值支持别名、忽略字段(,omitempty)、跳过字段(-)等高级用法,例如:Age intbson:"age,omitempty"``
- 若字段未导出(小写开头),默认不会被序列化,除非显式标记为 bson:",omitempty" 并确保可访问(需配合 bson.Unmarshal 的反射权限)
- mgo 已归档不再维护(官方推荐迁移到 mongo-go-driver),新项目建议优先选用官方驱动,其 bson 行为更明确且文档更完善,但仍需同样注意 struct tag 配置。
总结:不要依赖默认小写转换逻辑——尤其当 MongoDB Schema 需与 Go 字段名保持一致(如对接已有数据、遵循命名规范或与其他服务交互)时,务必为每个字段显式声明 bson tag,这是保证数据映射准确、可维护性的关键实践。











