必须用官方驱动mongo-go-driver,mgo已停更且不支持MongoDB 4.2+聚合特性;初始化用mongo.Connect(),聚合管道用[]bson.M,结果需显式Close游标并正确映射bson tag。

Go 用 mgo 还是 mongo-go-driver?别踩旧库坑
现在必须用官方驱动 mongo-go-driver,mgo 已停止维护且不支持 MongoDB 4.2+ 的多数聚合特性(比如 $facet、$setWindowFields),连连接字符串解析都可能 silently 失败。
常见错误现象:panic: runtime error: invalid memory address 或聚合结果为空但无报错——大概率是用了过时的 mgo 适配新服务端协议。
- 初始化客户端必须用
mongo.Connect(),传入context和带tls/auth的options.Client().ApplyURI(...) - 数据库和集合获取要显式调用
client.Database("db").Collection("coll"),不能靠全局变量或单例硬编码 - 所有聚合操作必须走
Collection.Aggregate(),不是Find()加手写过滤
Aggregate() 管道怎么写才不空跑?注意 BSON 类型和上下文
Go 里聚合管道是 []bson.M,不是 JSON 字符串,也不是结构体切片。写错类型会导致管道被忽略、返回空结果,且无任何错误提示。
使用场景:比如按日期分组统计日活,需要 $dateToString + $group,但 Go 中日期字段必须是 time.Time 类型,不能是字符串或 int64 时间戳(除非显式用 $toDate 转换)。
立即学习“go语言免费学习笔记(深入)”;
- 每个阶段用
bson.M{"$match": bson.M{"status": "active"}}这种形式,键名必须带$,值不能是 nil - 传入
Aggregate()的context必须带超时,例如ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second),否则网络卡住会永久阻塞 - 聚合结果游标(
*mongo.Cursor)必须显式Close(),否则连接泄漏;建议用defer cursor.Close(ctx)
聚合结果怎么解包?Decode() 和 All() 别混用
如果只取一条,用 cursor.Next() + cursor.Decode(&one);想全取,用 cursor.All()。二者底层行为不同:All() 会一次性拉取全部数据到内存,大数据量时 OOM 风险高;Next() 是流式读取,适合处理结果集不确定或很大的场景。
常见错误现象:定义了 struct 字段叫 UserCount,但 BSON 返回的是 count,没加 bson:"count" tag 就解包失败,字段保持零值也不报错。
- struct 字段必须用
bsontag 显式映射,比如Count int `bson:"count"`,大小写和下划线都不能错 - 聚合返回嵌套字段(如
{"stats": {"total": 123}})时,struct 要对应嵌套,不能 flatten 成平级字段 - 不确定字段类型?用
bson.M接收,但注意它本质是map[string]interface{},数值可能被转成float64,需手动断言
性能敏感时,$lookup 和 $facet 怎么写更稳?
$lookup 默认不走索引,如果被关联集合没在 foreignField 上建索引,聚合会变慢十倍以上;$facet 在内存中并行执行多个子管道,但总内存占用是各子管道之和,容易触发 errmsg: "Exceeded memory limit for $facet"。
使用场景:做多维度统计(如“今日新增 vs 留存率”),用 $facet 比发两次请求更省连接开销,但得控制每个子管道的数据量。
-
$lookup前确认目标集合在foreignField上有索引,命令:db.othercoll.createIndex({ "uid": 1 }) -
$facet内每个子管道开头加$limit或$match缩小数据集,避免内存溢出 - 必要时用
AllowDiskUse(true)选项(options.Aggregate().SetAllowDiskUse(true)),但仅限临时救急,不能替代优化
最常被忽略的一点:聚合管道里所有时间比较($gt、$lt)都必须用 time.Time 值,不是字符串。哪怕数据库存的是 ISO 格式字符串,也得先 $toDate 转换,否则比较永远为 false。









