distinct 是什么
distinct 返回集合中某个字段的全部去重值,结果是一个数组。它接受可选的查询条件参数,字段路径用点号表示嵌套层级,遇到数组会自动展开后再去重。执行方式分两类:字段上存在可用索引且条件能走索引时按索引扫描,否则退化为全集合扫描。结果必须装在一个 BSON 文档里返回,因此受 16MB 上限约束,取值特别多时会直接报错而不是被截断。
基本信息
| 语法 | db.collection.distinct(field, query) |
|---|---|
| 返回 | 去重后的值数组 |
| 索引利用 | 字段有序且条件可索引时避免扫全集合 |
| 结果上限 | 单个 BSON 文档 16MB,超出直接报错 |
| 字段路径 | 支持 "a.b" 嵌套与数组元素展开 |
| 所属系统 | MongoDB 全版本,mongosh 与各语言驱动均可用 |
典型使用场景
- 取枚举值:把状态、类型这类低基数字段的全部取值拉出来做筛选下拉框
- 数据体检:确认某字段有没有出现不该有的脏值或拼写变体
- 校验建模:看清标签类字段的真实取值范围,再决定要不要改成枚举
- 小范围对账:核对两个集合在某个字段上的取值集合是否一致
- 替代分组:值不多时用 distinct 比写聚合管道更省事
常见写法
常见写法
db.orders.distinct("status") // 全部去重状态
db.orders.distinct("sku", { status: "paid" }) // 只统计已支付订单的商品
db.orders.distinct("items.sku") // 数组字段展开后去重
db.orders.distinct("status", { // 限定时间范围,减少扫描量
ts: { $gte: ISODate("2026-01-01T00:00:00Z") }
})
db.runCommand({ distinct: "orders", key: "status" }) // 驱动层可用 runCommand 形式参数与限制读法
| 项 | 含义 | 注意 |
|---|---|---|
| field | 要统计的字段路径 | 点号访问嵌套,数组会自动展开 |
| query | 过滤条件 | 能用索引就快,否则全集合扫描 |
| 返回值 | 去重后的值列表 | 形态是数组,直接给前端很方便 |
| 16MB 上限 | 结果文档大小限制 | 超限报错而不是返回部分结果 |
| null 项 | 字段缺失的文档 | 值缺失时结果里会出现 null |
对高基数字段(用户 ID、订单号)做 distinct 会返回巨大数组,既占内存也容易撞 16MB 上限。这类需求应改成聚合 $group,按值统计条数,只取需要的部分。
distinct 会读取全部匹配文档,在没有合适索引的大集合上是重操作,线上业务高峰执行容易拉高 IO 与响应时间。