MongoDB的聚合管道里,$sortByCount是一个专门用来按某个表达式的值分组、统计每组文档数量、并且自动按照数量从多到少排序的便捷阶段。它把原本需要$group和$sort两个步骤才能完成的事情压缩成了一个阶段,在写统计类查询时非常实用。理解它的执行逻辑,有助于我们在做频次分析、标签统计、分类汇总时写出更简洁也更高效的聚合代码。

一、$sortByCount的基本语法与等价展开
在聚合管道中,$sortByCount阶段只接受一个表达式作为参数,这个表达式决定了按什么字段或者经过什么计算之后的值来进行分组。它的写法是{ $sortByCount: <expression> },其中表达式可以是普通字段路径如$status,也可以是更复杂的计算表达式。管道执行到这一阶段时,会先按照表达式计算结果将文档分组,然后统计每个分组内的文档数量,最后以count字段做降序输出。
从语义上讲,$sortByCount完全等价于先使用$group阶段按表达式分组并求sum,再使用$sort阶段按count降序。例如下面两段聚合逻辑的结果是一样的。第一段是展开写法,第二段是简写写法,但数据库内部优化器对$sortByCount有更直接的执行路径,不必显式构造中间分组阶段。
// 等价展开写法
db.orders.aggregate([
{ $group: { _id: "$status", count: { $sum: 1 } } },
{ $sort: { count: -1 } }
]);
// 使用 $sortByCount 的写法
db.orders.aggregate([
{ $sortByCount: "$status" }
]);
需要注意的是,$sortByCount输出的文档结构固定为{ _id: <分组值>, count: <数量> },_id就是分组依据的值,count是该值出现的文档数。由于它内部已经包含了排序,我们没必要在后面再追加一个$sort,否则属于多余操作。如果业务要求升序或者按其他字段排序,那就不能直接用$sortByCount,而必须回到$group加$sort的写法。
二、实际应用场景与代码示例
最常见的用法就是统计集合中某个字段各个取值的出现次数,比如统计用户表中来自不同城市的用户量排名。假设有一个users集合,每个文档有city字段,我们想看哪个城市用户最多,直接用$sortByCount即可。这种查询在运营报表、热门标签分析里非常普遍,比起手动分组排序,代码可读性更高。
下面这个例子统计各城市用户数并取前5名。由于$sortByCount已经排好序,我们只需要用$limit截断即可。如果数据量较大,建议在管道前面先加$match缩小范围,或者确保city字段上有索引,这样分组阶段扫描的文档更少。
db.users.aggregate([
{ $match: { registered: true } },
{ $sortByCount: "$city" },
{ $limit: 5 }
]);
另一个场景是对数组字段展开后的元素计数。比如文章文档里有一个tags数组,我们想统计所有标签被使用的频次。这时可以先用$unwind把数组拆开,再交给$sortByCount处理。这样每个标签成为独立文档,分组计数自然就得到了标签热度排行。
db.posts.aggregate([
{ $unwind: "$tags" },
{ $sortByCount: "$tags" }
]);
在这些场景中,$sortByCount显著减少了聚合语句的嵌套层级。不过要记住,它只能基于单一表达式分组,不能像$group那样同时算出多个累加值。如果除了计数还要算平均金额、最大时间等,就必须用$group明确写出每个累加器。
三、性能特征与使用限制
从执行计划角度看,$sortByCount会在内存中维护分组状态。当分组基数很高,也就是不同值非常多的时候,它会消耗较多内存,甚至可能触发MongoDB关于聚合内存使用的限制。在生产环境处理大集合时,应当尽量在$sortByCount之前使用$match过滤掉无关文档,或者利用索引让前面的阶段更高效。
另外,$sortByCount不支持自定义排序方向,永远都是count降序。如果我们需要按分组值本身排序,或者按count升序,就只能放弃这个语法糖,改用$group后接$sort。还有一点,它不能接收多个分组字段,也就是说无法像{ $group: { _id: { a: "$a", b: "$b" } } }那样做复合分组,只能传一个表达式,复合分组需提前用$project拼成单个字段。
// 复合分组不能用 $sortByCount 直接写,需要先计算
db.logs.aggregate([
{ $project: { key: { $concat: ["$type", "_", "$level"] } } },
{ $sortByCount: "$key" }
]);
总体来看,$sortByCount是MongoDB聚合里非常实用的语法糖,适合单一维度频次统计并直接排序的场景。在清楚它不支持升序、不支持多字段分组、且需注意内存消耗的前提下,合理使用可以让统计类聚合更短平快,也降低脚本维护成本。
MongoDBaggregation_pipelinesortByCount修改时间:2026-08-13 17:16:04