
本文解释了使用go语言和mgo驱动向mongodb插入结构体时仅生成空文档的常见原因:结构体字段未导出(即首字母小写),导致mgo无法访问和序列化字段值。
在Go语言中,只有首字母大写的字段才是导出(exported)字段,才能被其他包(如 mgo)通过反射机制读取和序列化。而原始代码中定义的 Result 结构体所有字段均为小写开头(nid, timestamp, hexhash, addr),属于非导出字段,因此 mgo 在执行 Insert() 时无法获取其值,最终只写入了默认的 _id 字段,其余字段被忽略——表现为 MongoDB 中仅存空文档。
✅ 正确做法是将结构体字段改为大驼峰命名(Public Exported Fields),并可选地通过 bson 标签明确指定数据库字段名,提升可维护性与兼容性:
type Result struct {
Nid string `bson:"nid"`
Timestamp int64 `bson:"timestamp"`
Hexhash string `bson:"hexhash"`
Addr string `bson:"addr"`
}创建实例时保持不变:
r := Result{
Nid: hex_id,
Timestamp: int64(msg.timestamp.Unix()),
Hexhash: hexhash,
Addr: msg.addr.String(),
}
fmt.Printf("Inserting: %+v\n", r) // 调试建议:使用 %+v 查看字段名与值
err := h.c.Insert(r)
if err != nil {
log.Fatal("Failed to insert into MongoDB:", err)
}⚠️ 注意事项:
立即学习“go语言免费学习笔记(深入)”;
- mgo(及后续的 mongo-go-driver)均依赖 Go 的反射机制,非导出字段永远不可见,无论是否添加 bson 标签;
- 若需保留 Go 变量命名习惯(如 CreatedAt 对应 created_at),务必配合 bson 标签映射,否则数据库字段名将默认为大驼峰(如 CreatedAt → createdat);
- 建议为所有 BSON 字段添加 omitempty(如 `bson:"nid,omitempty"`)以避免零值字段意外写入;
- mgo 已归档,新项目推荐迁移到官方驱动 go.mongodb.org/mongo-driver/mongo,其序列化规则一致(仍要求字段导出)。
总结:Go 结构体写入 MongoDB 的前提不是“定义了字段”,而是“字段可被外部包导出并反射”。一次首字母大写的修正,即可解决 90% 的空文档插入问题。










