是什么
$count 是聚合管道里的计数阶段,语法就一句 { $count: "字段名" },语义等价于 { $group: { _id: null, 字段名: { $sum: 1 } } } 再加一次投影。它的价值在于能挂在 $match、$unwind、$lookup 之后,统计过滤或展开后的文档数,而单独的 count 命令做不到这一点。
基本信息
| 语法 | { $count: "字段名" } |
|---|---|
| 等价写法 | $group 按 _id: null 分组并 $sum: 1 |
| 输出 | 单个文档,只含指定字段 |
| 位置 | 常作为管道末段:之后的阶段拿到的只有一条计数文档 |
| 兄弟方法 | countDocuments(带条件)、estimatedDocumentCount(不带条件,走元数据估算) |
典型使用场景
- 条件计数:统计状态为 paid 的订单数,比先拉到客户端再 length 高效得多
- 展开后计数:$unwind 数组字段后统计总元素个数,用于核对一对多数据量
- 关联后计数:$lookup 之后统计有关联记录的文档数,排查悬空引用
- 去重后计数:先 $group 按业务主键去重,再用 $count 得到去重数量
- 质量巡检:统计空值或异常字段的条数,作为数据质量指标
计数示例
计数示例
db.orders.aggregate([
{ $match: { status: "paid" } }, # 先用索引友好的条件缩小范围
{ $count: "paidOrders" } # 输出单个文档 { paidOrders: N }
])
db.orders.aggregate([ # 展开数组后统计元素总数
{ $match: { status: "paid" } },
{ $unwind: "$items" },
{ $count: "itemCount" }
])
db.orders.countDocuments({ status: "paid" }) # 单纯条件计数,走查询引擎更快
db.orders.estimatedDocumentCount() # 估算总量,读元数据,不接条件三种计数方式对比
| 方式 | 能否带条件 | 代价 | 适用 |
|---|---|---|---|
| $count 阶段 | 可以,配合前序阶段 | 按管道实际扫描量 | 展开、关联、去重后的计数 |
| countDocuments | 可以 | 走查询与索引 | 单纯条件计数 |
| estimatedDocumentCount | 不可以 | 读元数据,最快 | 总量概览、监控看板 |
| 旧版 count() | 可以 | 已废弃 | 迁移到上面两种 |
estimatedDocumentCount 读的是集合元数据,不扫描数据,因此在大集合上毫秒级返回;代价是异常关闭后可能有偏差,需要精确值时不能用它。
在分片集群上带条件的计数要向各分片分发并汇总,代价随分片数增加;把高频计数做成定时落库的汇总表,比每次实时统计更稳妥。