必须将$match放在$sort前才能利用索引加速,因聚合管道流式处理,先过滤再排序可大幅降低内存与耗时;$sort需紧邻$match且字段类型一致、有对应索引,否则Top-N查询易失效。
直接用 $sort + $limit 就能拿到 TopN 热点内容,但真正在生产环境跑得稳、查得快,关键不在“能不能做”,而在“字段有没有索引”“排序字段类型是否一致”“聚合阶段顺序是否合理”。
$sort 必须紧挨着 $match 放?聚合管道是流式处理,每阶段输出作为下一阶段输入。如果先 $group 再 $sort,就得对全部分组结果排序;而如果先 $match 过滤出最近 7 天数据,再 $sort,内存和耗时会大幅下降。
$group 统计所有历史热度,再 $sort —— 即使只取前 10,也要算完全部分组$match → $sort → $limit(适用于按时间/热度原始字段排序)$sort 放在 $addFields 或 $project 之后created_at 和 view_count 哪个更适合做排序主字段?取决于“热点”的定义:是最新发布的内容,还是被最多人看的内容?两者策略完全不同。
created_at 降序,配合 db.posts.createIndex({ created_at: -1 })
view_count 降序,但注意该字段必须是数字类型——如果存成字符串("12345"),$sort 会按字典序排,"999" > "10000"
view_count 降序,相同热度时按 created_at 降序,避免老内容长期霸榜:{$sort: { view_count: -1, created_at: -1 }}
$lookup 关联用户信息会影响 TopN 性能吗?会,而且影响很大——尤其当关联集合很大或没建好索引时。$lookup 在 $sort 之前执行,意味着你要为全部候选文档做关联,哪怕最后只留前 10 条。
$match + $sort + $limit 拿到 ID 列表,再用 find({ _id: { $in: [...] } }) 单独查详情$lookup 时,确保被关联集合在 localField 上有索引(如 db.users.createIndex({ _id: 1 }))$lookup 后加 $sort——关联结果可能已打乱原始热度顺序,且无法利用索引真正卡住性能的,往往不是聚合语法写错,而是 view_count 字段类型不统一、created_at 缺少索引、或者把 $lookup 塞进 TopN 主流水线里。上线前用 explain() 看一眼执行计划,比反复调参数更管用。