如何优化MongoDB聚合查询?附查询代码及索引添加疑问
MongoDB聚合查询优化方案
一、索引优化(必做)
针对你的查询场景,给两个集合创建针对性索引,直接提升关联和过滤的效率:
- search_history集合:创建复合索引,覆盖关联字段和时间过滤字段
db.search_history.createIndex({ search_id: 1, created_at: 1 })
这个索引能让MongoDB快速过滤created_at符合条件的记录,同时加速与positive集合的关联匹配,避免全表扫描。
- positive集合:给关联字段创建单字段索引
db.positive.createIndex({ search_id: 1 })
用于加速$lookup时的search_id匹配,减少集合扫描的开销。
二、查询逻辑优化(推荐)
原查询从positive出发关联search_history,若positive数据量较大,会触发大量关联查询。建议反转查询顺序,先从search_history过滤聚合,再关联positive,大幅减少处理的数据集:
const tags = await mongo .collection("search_history") .aggregate<{ word: string; count: number }>([ // 第一步:先过滤时间范围,缩小初始数据集 { $match: { created_at: { $gt: prevSunday.toISOString() }, }, }, // 第二步:按search_id和url去重,避免同一url重复统计 { $group: { _id: { search_id: "$search_id", url: "$url" }, }, }, // 第三步:关联positive集合,获取对应的word字段 { $lookup: { from: "positive", localField: "_id.search_id", foreignField: "search_id", as: "positive", // 只返回需要的word字段,减少数据传输量 pipeline: [{ $project: { word: 1, _id: 0 } }], }, }, // 过滤掉未匹配到positive的无效记录 { $match: { positive: { $ne: [] } } }, // 展开positive数组(假设一个search_id对应一个positive文档) { $unwind: "$positive" }, // 按word分组,统计去重后的url数量 { $group: { _id: "$positive.word", count: { $sum: 1 }, }, }, // 重命名字段为目标格式 { $project: { _id: 0, word: "$_id", count: 1, }, }, // 排序取前50 { $sort: { count: -1 } }, { $limit: 50 }, ]) .toArray();
优化逻辑说明:
- 先过滤
search_history的时间范围,直接减少后续处理的数据量; - 提前对
search_id+url去重,避免后续重复统计; - 去掉原查询中复杂的
$reduce+$concatArrays操作,直接通过$sum统计数量,逻辑更简洁高效; - 关联时只返回需要的
word字段,减少数据传输开销。
内容的提问来源于stack exchange,提问作者chovy
相关产品推荐
相关产品推荐

