必须使用官方 mongo-go-driver,mgo 已停更且在 mongodb 4.2+ 上静默失败;aggregate() 参数须为 []bson.d 或 []bson.m,不可用 json 字符串或 map[string]interface{};需严格匹配 bson 类型与字段路径,时间字段须为 time.time,游标须显式 close() 并带超时 context。

必须用官方驱动 mongo-go-driver,mgo 已停更且在 MongoDB 4.2+ 上会静默失败——比如 $facet 不生效、连接字符串解析丢参数、聚合结果为空却不报错。
Aggregate() 管道参数必须是 []bson.D 或 []bson.M,不能是 JSON 字符串或 map[string]interface{}
Go 官方驱动不接受任意类型传给 Collection.Aggregate()。错用类型会导致编译通过但运行时返回空结果,或 panic:invalid pipeline operator。
-
bson.D是有序切片,推荐用于含多次同名操作(如多个$addFields)或依赖顺序的阶段(如$lookup后紧跟$unwind) -
bson.M是无序 map,写起来快,但$group的_id字段若含多个键,旧版 MongoDB 可能因顺序不一致出错 - 每个阶段必须是独立的
bson.D,例如[]bson.D{{{ "$match", ... }}, {{ "$sort", ... }}};不能写成bson.D{{"$match",...},{"$sort",...}}
$group 和 $match 阶段的字段路径与类型必须严格匹配 BSON 规范
Go 没有 JS 那种动态字段语法,所有 key 都得硬编码,值类型错一点就静默失效。
-
$match中时间字段必须是time.Time类型,不能传int64时间戳(除非显式用$toDate转换) -
$group的_id不能写成字符串"status",得是bson.D{{"_id", "$status"}}或bson.M{"_id": "$status"} - 聚合表达式如计数必须用
"$sum",不是"count";最大值用"$max",不是"max" -
$lookup的from、localField、foreignField必须拼写完全一致——拼错不会报错,只返回空数组
游标必须显式 Close(),解码要用 Next() 或 All() 区分场景
不 Close() 会导致连接泄漏;不区分读取方式可能 OOM 或漏错误。
- 传给
Aggregate()的context必须带超时,例如ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second),否则网络卡住会永久阻塞 - 只取一条用
cursor.Next()+cursor.Decode(&one);全取才用cursor.All() -
All()会一次性拉全部数据进内存,大数据量时风险高;Next()是流式读取,适合不确定结果集大小的场景 - 遍历时不能只看
Next()返回false就认为结束,必须检查cursor.Err()判断是否因超时或断连中断
struct 解包必须用 bson tag 显式映射,嵌套字段不能 flatten
字段名大小写、下划线、嵌套结构必须和 BSON 返回完全一致,否则字段保持零值且不报错。
- 比如 BSON 返回
{"count": 123},struct 得写Count int `bson:"count"`,写成Count int `bson:"Count"`就失败 - 返回
{"stats": {"total": 123}},struct 就得嵌套定义Stats struct{ Total int `bson:"total"` } `bson:"stats"`,不能直接写Total int `bson:"stats.total"` - 字段类型不确定时可用
bson.M接收,但它本质是map[string]interface{},后续取值要类型断言
最容易被忽略的是:聚合管道里所有时间操作默认要求字段是 time.Time 类型,而数据库里存的很可能是字符串或秒级时间戳——不加 $toDate 或 $convert 转换,$dateToString 这类阶段就什么也不干。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











