在MongoDB中不使用$accumulator和自定义JS函数计算最长连胜
获取MongoDB中最长连胜记录(无JS依赖方案)
针对你提供的文档集合,以下是完全依赖MongoDB原生聚合操作符的解决方案,无需自定义JS函数:
完整聚合管道
db.collection.aggregate([ // 1. 按时间顺序排序,确保连胜按发生顺序统计 { $sort: { createdAt: 1 } }, // 2. 用窗口函数标记连胜分组:同一连胜的文档分配相同group_id { $setWindowFields: { partitionBy: null, // 全局窗口,所有文档在同一分区 sortBy: { createdAt: 1 }, output: { group_id: { $sum: { $cond: [ // 首次文档或当前win与前一个不同时,分组ID+1 { $or: [ { $eq: [ { $lag: "$win" }, null ] }, { $ne: [ "$win", { $lag: "$win" } ] } ] }, 1, 0 ] } } } } }, // 3. 按分组ID聚合,统计每组文档数量(即连胜长度),保留win状态 { $group: { _id: { group_id: "$group_id", win: "$win" }, streak_length: { $count: {} } } }, // 4. 仅保留胜利的连胜记录 { $match: { "_id.win": true } }, // 5. 取最长连胜长度,无胜利则返回0 { $group: { _id: null, max_win_streak: { $max: "$streak_length" } } }, { $project: { _id: 0, max_win_streak: { $ifNull: [ "$max_win_streak", 0 ] } } } ])
各阶段说明
- $sort:必须按
createdAt升序排列,保证连胜统计的时间顺序,避免分组错乱。 - $setWindowFields:通过
$lag获取前一个文档的win值,用$cond判断是否开启新连胜组,再用$sum生成唯一group_id——同一连胜序列的文档会拥有相同group_id。 - $group(第一次):按
group_id和win分组,用$count统计每组长度,得到每个连胜序列的持续次数。 - $match:过滤掉失败的连胜记录,只保留胜利相关的统计结果。
- $group(第二次):全局聚合取最大连胜长度,用
$ifNull处理无胜利记录的边界情况,返回0。
针对你提供的示例数据,执行后会返回{ "max_win_streak": 2 },符合预期。
内容的提问来源于stack exchange,提问作者Talles Hentges
相关产品推荐
相关产品推荐

