MongoDB提供了多种查看集合索引的方式,最常见的是db.collection.getIndexes()和listIndexes命令,但从4.4版本开始,聚合框架引入了$listIndexes阶段,让索引查看也能融入管道操作。这个看似简单的功能,在需要将索引信息与其他数据源做关联分析、或者在脚本中统一用聚合接口处理任务时,能带来不少便利。本文将详细介绍$listIndexes的语法、输出结构、权限要求以及典型使用场景。

$listIndexes的基本语法与输出结构
$listIndexes是聚合管道的一个初始阶段,意思是它必须出现在管道的第一个位置,前面不能再接$match、$sort等其他阶段。它的语法非常简洁,既可以完全不带参数,也可以指定一个可选的options文档。
// 不带参数,列出当前集合的所有索引
db.users.aggregate([
{ $listIndexes: {} }
])
// 带参数的形式,cursor选项控制批处理文档数量
db.users.aggregate([
{ $listIndexes: { cursor: { batchSize: 10 } } }
])
输出的每个文档代表一个索引,主要字段包括:v表示索引格式版本,目前主流版本是2;key是索引键模式,指明哪些字段参与索引以及排序方向;name是索引名称,如果不指定,MongoDB会按照字段名和方向自动生成。此外还可能包含unique、sparse、expireAfterSeconds、partialFilterExpression等属性字段,取决于建索引时的配置。
假设我们在users集合上建了一个复合索引和一个TTL索引,用$listIndexes查询会得到类似下面的结果:
// 建索引
db.users.createIndex({ name: 1, age: -1 })
db.users.createIndex({ createdAt: 1 }, { expireAfterSeconds: 3600 })
// 查看索引
db.users.aggregate([ { $listIndexes: {} } ])
// 输出示例
[
{ v: 2, key: { _id: 1 }, name: '_id_' },
{
v: 2,
key: { name: 1, age: -1 },
name: 'name_1_age_-1'
},
{
v: 2,
key: { createdAt: 1 },
name: 'createdAt_1',
expireAfterSeconds: 3600
}
]
可以看到,_id索引永远排在第一位,这是MongoDB自动创建的默认索引,无法删除。TTL索引会额外带一个expireAfterSeconds字段,表示文档在指定秒数后自动过期删除。理解这些字段的含义,是做索引分析的前提。
$listIndexes与getIndexes、listIndexes命令的区别
很多初学者会疑惑,既然db.collection.getIndexes()一条命令就能拿到索引列表,为什么还要用聚合阶段来做这件事?两者在功能上确实高度重合,但底层机制和使用方式存在一些差异。
首先从实现层面看,getIndexes()本质上是shell对listIndexes数据库命令的封装,而$listIndexes则是聚合框架的一个阶段,它同样依赖listIndexes命令的能力。所以两者的输出内容完全一致,包括字段和顺序。区别在于使用形态:聚合阶段可以和后续管道阶段组合,这是命令形式做不到的。
比如你想快速找出所有包含某个字段的索引,直接用$listIndexes配合$filter或$match就能实现:
db.users.aggregate([
{ $listIndexes: {} },
{ $match: { "key.name": { $exists: true } } }
])
// 进一步统计索引总数与唯一索引数量
db.users.aggregate([
{ $listIndexes: {} },
{ $group: {
_id: null,
total: { $sum: 1 },
uniqueCount: { $sum: { $cond: ["$unique", 1, 0] } }
} }
])
这种组合能力在批量巡检多个集合、生成索引报表时特别有用。当然也要注意,$listIndexes后面可以继续接投影、分组等阶段,但前面不能有任何阶段,否则会直接报错。
权限要求与常见报错处理
在启用了访问控制的集群中,执行$listIndexes需要集合级别的listIndexes权限动作。普通读权限read角色默认包含这个动作,所以拥有读权限的用户通常可以顺利执行。但如果只授予了非常细粒度的自定义角色,就要确认权限定义里包含了listIndexes动作。
常见的报错有几种情况。第一种是把$listIndexes放在管道中间位置,错误信息通常是"$listIndexes is only valid as the first stage in a pipeline",解决办法就是把它移到管道开头。第二种是在不存在的集合上执行,这时不会报错,而是返回空结果,这一点和某些命令的行为不同,写脚本时要注意区分集合不存在与集合无索引两种情况。
第三种是版本兼容问题。$listIndexes在MongoDB 4.4及以上版本才可用,如果在旧版本上运行,驱动或shell会提示不认识该阶段。对于需要兼容旧版本的脚本,建议做版本判断,旧环境退回使用db.collection.getIndexes()。另外在分片集群中,$listIndexes的行为与listIndexes命令一致,会返回各分片索引的合并视图,不需要额外处理。
掌握$listIndexes之后,还可以结合$indexStats阶段一起使用,后者提供索引的访问统计信息如命中次数、扫描次数等。两个阶段配合,先列出索引清单,再分析每个索引的使用频率,就能很容易找出从未被使用过的冗余索引,为索引清理工作提供数据支撑,这也是索引运维中最常见的实践路径。
MongoDB聚合管道$listIndexes修改时间:2026-09-09 09:08:42