
在Go中使用mgo驱动插入结构体到MongoDB时,若仅 _id 字段被写入而其余字段为空,根本原因是结构体字段未导出(即首字母小写),导致mgo无法通过反射访问并序列化这些字段。
在Go中使用mgo驱动插入结构体到MongoDB时,若仅 `_id` 字段被写入而其余字段为空,根本原因是结构体字段未导出(即首字母小写),导致mgo无法通过反射访问并序列化这些字段。
Go语言的反射机制(reflect package)仅能访问导出字段(exported fields)——即首字母为大写的字段。mgo 依赖反射将结构体字段映射为 BSON 文档,若字段名以小写字母开头(如 user_session_id_str),即使已正确设置值,mgo 也会忽略该字段,最终仅插入 _id(因其是导出字段且显式赋值)。
✅ 正确做法:将所有需持久化的字段名首字母大写,并保持 BSON tag 小写以兼容 MongoDB 字段命名习惯:
type AN_Track_Log struct {
ID bson.ObjectId `bson:"_id,omitempty"`
UserSessionIDStr string `bson:"user_session_id_str"`
GoogleAnalyPixelIDStr string `bson:"googleanaly_pixel_id_str"`
PerfAudPixelIDStr string `bson:"perfaud_pixel_id_str"`
SiteIDStr string `bson:"site_id_str"`
MetricStr string `bson:"metric_str"`
ValueStr string `bson:"value_str"`
EventStr string `bson:"event_str"`
LocationIDStr string `bson:"location_id_str"`
RefererStr string `bson:"referer_str"`
TrackOriginStr string `bson:"track_origin_str"`
FingerprintStr string `bson:"fingerprint_str"`
// ... 其他字段同理
}⚠️ 注意事项:
- ID 字段建议命名为 ID(而非 Id),更符合 Go 命名惯例;bson:"_id,omitempty" 保持不变,确保自动生成 ObjectId。
- 字段名大小写变更后,务必同步更新所有赋值代码(如 p_track_log.UserSessionIDStr = "abc")。
- 若需兼容旧有 JSON/BSON 序列化逻辑,可额外添加 json:"user_session_id_str" tag,但非必需。
- mgo 已归档(不再维护),生产环境推荐迁移到官方驱动 mongo-go-driver,其同样遵循导出规则,但 API 更现代、类型更安全。
? 总结:Go 结构体字段必须导出(首字母大写)才能被 mgo(及绝大多数 Go 序列化库)识别和写入数据库。这是 Go 语言设计原则的直接体现,而非 mgo 的 bug —— 修复只需调整字段命名,无需修改逻辑或依赖。