MongoDB聚合查询:动态统计最大年份前20年的电影数量
问题描述
MongoDB中存储了多部电影文档,包含title(电影标题)和year(上映年份)字段,示例文档如下:
{"_id" : ObjectId("63a994974ac549c5ea982d2b"),"title" : "Destroyer","year" : 2018}, {"_id" : ObjectId("63a994974ac549c5ea982d2a"),"title" : "Aquaman","year" : 2014}, {"_id" : ObjectId("63a994974ac549c5ea982d29"),"title" : "On the Basis of Sex","year" : 1998}, {"_id" : ObjectId("63a994974ac549c5ea982d28"),"title" : "Holmes and Watson","year" : 1940}, {"_id" : ObjectId("63a994974ac549c5ea982d27"),"title" : "Conundrum: Secrets Among Friends","year" : 1957}, {"_id" : ObjectId("63a994974ac549c5ea982d26"),"title" : "Welcome to Marwen","year" : 2000}, {"_id" : ObjectId("63a994974ac549c5ea982d25"),"title" : "Mary Poppins Returns","year" : 1997}, {"_id" : ObjectId("63a994974ac549c5ea982d24"),"title" : "Bumblebee","year" : 2018}
需求是统计上映年份处于文档中最大年份及其前20年区间内的电影数量,示例中最大年份为2018,区间为1998-2018,期望结果为4部。
尝试代码
var query1 = {"$addFields": {maxium: {$max: "$year"}, minimum : {$subtract: [{$max: "$year"}, 20]}}} var filter = {"year": {"$lte": maximum, "$gte": minimum}} var logic = {$match: {$and: [filter]}} var query1 = {$group: {"_id": null, "count": {$sum:1}}} var stage = [logic, query1] db.movies.aggregate(stage)
错误信息
{"message" : "maximum is not defined", "stack" : "script:3:32"}
错误原因
- 变量未定义:代码中
maximum和minimum是未声明的变量,聚合阶段按顺序执行,无法在前面阶段直接引用后续阶段才会生成的字段值。 - 聚合管道逻辑缺失:定义的
$addFields阶段未加入到聚合管道stage中,等于完全没执行最大年份计算,直接匹配自然报错。 $max使用错误:$addFields中直接用$max: "$year"只会取当前文档的年份值,而非整个集合的全局最大年份,需通过$group先计算全局最大值。
正确实现方案
方式一:单聚合管道完成
通过聚合管道分步计算全局最大年份、筛选区间内文档、统计数量:
db.movies.aggregate([ // 计算全局最大年份,并保留所有文档数据 { $group: { _id: null, maxYear: { $max: "$year" }, movies: { $push: "$$ROOT" } } }, // 计算区间最小值,筛选符合条件的电影 { $project: { eligibleMovies: { $filter: { input: "$movies", cond: { $and: [ { $gte: ["$$this.year", { $subtract: ["$maxYear", 20] }] }, { $lte: ["$$this.year", "$maxYear"] } ] } } } } }, // 统计符合条件的电影数量 { $project: { count: { $size: "$eligibleMovies" }, _id: 0 } } ])
方式二:分步查询(更直观)
先获取全局最大年份,再基于年份区间统计数量:
// 获取集合中的最大年份 var maxYear = db.movies.find().sort({year: -1}).limit(1)[0].year; // 计算区间最小年份 var minYear = maxYear - 20; // 统计区间内的电影数量 db.movies.countDocuments({ year: { $gte: minYear, $lte: maxYear } })
内容的提问来源于stack exchange,提问作者DatBigD
相关产品推荐
相关产品推荐

