MongoDB多$project阶段聚合百分比查询优化咨询
MongoDB聚合查询优化建议(技能需求占比计算)
需求背景
计算过去90天内各技能的需求占比,现有查询可得到预期结果,但存在优化空间。
示例文档
{ "_id": { "$oid": "630a2ba9fe850ebc2d2f4a25" }, "category": { "name": "SQL", "path": ",web development,", "id": { "$oid": "62fe35f3f1793d2014bfe05f" } }, "createdAt": { "$date": { "$numberLong": "1661610921812" } } }
原查询存在的问题
- 窗口函数写法不规范:第一个
$project阶段中total: {$sum:count}属于隐式窗口函数用法,未明确声明窗口范围,可读性差,后续维护易出错。 - 冗余管道阶段:分两个
$project阶段处理占比计算,增加了不必要的管道处理开销。 - 性能优化缺失:未针对
$match阶段的createdAt字段创建索引,数据量较大时过滤速度慢。
优化后的查询
// 提前计算90天前的时间,避免管道内重复计算 const ninetyDaysAgo = new Date(Date.now() - 90 * 24 * 60 * 60 * 1000); const SkillsInDemand = await Job.aggregate([ // 过滤过去90天数据,依赖索引加速 { $match: { createdAt: { $gte: ninetyDaysAgo } } }, // 分组统计各技能的需求数量 { $group: { _id: "$category.name", count: { $sum: 1 } } }, // 用窗口函数计算所有技能的总需求数,每个文档都能获取该值 { $setWindowFields: { output: { total: { $sum: "$count" } } } }, // 计算占比并格式化结果(保留2位小数可选) { $project: { _id: 1, percentage: { $round: [ { $multiply: [ { $divide: ["$count", "$total"] }, 100 ] }, 2 ] } } }, // 按占比降序排序 { $sort: { percentage: -1 } } ]);
优化说明
- 索引优化:给
createdAt字段创建单字段索引,大幅提升$match阶段的数据过滤速度:db.Job.createIndex({ createdAt: 1 }) - 清晰的窗口函数用法:使用
$setWindowFields明确计算总需求数,逻辑直观,可读性强。 - 减少管道阶段:合并原查询的两个
$project阶段,降低管道处理的性能开销。 - 结果格式化:通过
$round函数将百分比保留2位小数,输出结果更整洁(可根据需求调整小数位数)。
优化后输出示例
[ { "_id": "Python", "percentage": 75 }, { "_id": "SQL", "percentage": 16.67 }, { "_id": "Flutter", "percentage": 8.33 } ]
内容的提问来源于stack exchange,提问作者Fawad 4bros
相关产品推荐
相关产品推荐

