MongoDB 命令速查表 - MongoDB 数据库常用命令大全
面向用文档型数据库、需要保证读取够快的后端开发者。MongoDB 的价值是文档灵活、无固定 Schema,但这种自由要付出代价——不在筛选字段上建索引,查询就会退化成分集合扫描。读完能为某个集合设计 CRUD 查询、用 explain("executionStats") 确认是否命中索引、用 match/group/sort 搭出聚合管道,并分辨哪些能力复制集能保证、哪些必须靠分片。
典型使用场景
面向使用 MongoDB 做存储的开发者。本表覆盖数据库与集合操作、文档 CRUD、查询操作符、索引管理、聚合管道与复制分片六组。真正影响生产性能的两个点在本表里被单独强调:查询操作符的使用方式(`$gt`/`$in` 等,避免拉回内存过滤)与索引创建(无索引的大集合查询是全集合扫描)。聚合管道部分值得逐段读——`$match` 放在最前、`$project` 提前裁剪字段能显著减少数据量。
数据库操作 Database 6
show dbsuse dbnamedbdb.stats()db.dropDatabase()show collections文档操作 Document CRUD 9
db.collection.insertOne({name: "tom"})db.collection.insertMany([{...}, {...}])db.collection.find()db.collection.find({age: {$gt: 18}})db.collection.findOne({name: "tom"})db.collection.updateOne({name: "tom"}, {$set: {age: 20}})db.collection.updateMany({age: {$lt: 18}}, {$set: {status: "minor"}})db.collection.deleteOne({name: "tom"})db.collection.deleteMany({age: {$lt: 18}})查询操作符 Query Operators 8
{field: value}{field: {$gt: value}}{field: {$lt: value}}{field: {$ne: value}}{field: {$in: [v1, v2]}}{$and: [{...}, {...}]}{$or: [{...}, {...}]}{field: /regex/i}索引管理 Index 6
db.collection.createIndex({field: 1})db.collection.createIndex({f1: 1, f2: 1})db.collection.createIndex({field: 1}, {unique: true})db.collection.createIndex({field: 1}, {expireAfterSeconds: 3600})db.collection.getIndexes()db.collection.dropIndex("index_name")聚合管道 Aggregation 7
db.collection.aggregate([{$match: {age: {$gt: 18}}}]){$group: {_id: "$field", count: {$sum: 1}}}{$project: {name: 1, _id: 0}}{$sort: {field: -1}}{$limit: 10} / {$skip: 20}{$unwind: "$arrayField"}{$lookup: {from: "other", localField: "id", foreignField: "_id", as: "joined"}}复制与分片 Replication & Sharding 7
rs.status()rs.conf()rs.initiate()rs.add("host:port")rs.remove("host:port")sh.status()sh.enableSharding("dbname")参数矩阵
| 参数 | 作用 | 示例 |
|---|---|---|
use dbname | 切换数据库(不存在会自动创建) | use dbname |
show dbs / show collections | 列出数据库 / 当前库的集合 | show collections |
insertOne / insertMany | 插入单条 / 批量 | db.c.insertMany([{...}]) |
findOne / find | 查单条 / 全部 | db.c.find({age: {$gt: 18}}) |
$gt / $gte / $lt / $lte | 大小比较 | {age: {$gte: 18}} |
$ne / $in | 不等于 / 在列表中 | {_id: {$in: [1, 2]}} |
$and / $or | 逻辑与 / 或 | {$or: [{a: 1}, {b: 2}]} |
/regex/i | 正则匹配(i 忽略大小写) | {name: /tom/i} |
updateOne / updateMany | 更新单条 / 批量,配合 $set | db.c.updateMany({}, {$set: {st: "ok"}}) |
createIndex 复合 | 多字段索引,顺序影响效率 | db.c.createIndex({f1: 1, f2: 1}) |
unique: true | 唯一索引,重复插入报错 | db.c.createIndex({email: 1}, {unique: true}) |
expireAfterSeconds | TTL 索引,到期自动删除 | db.c.createIndex({ts: 1}, {expireAfterSeconds: 3600}) |
$group / $project | 分组统计 / 字段投影 | {$group: {_id: "$city", n: {$sum: 1}}} |
$unwind / $lookup | 展开数组 / 跨集合关联 | {$lookup: {from: "b", localField: "id", as: "j"}} |
易错点与避坑指南
现象查询大集合时响应极慢,explain 显示 COLLSCAN。
原因查询字段没有索引,MongoDB 做全集合扫描。
处置用 db.collection.getIndexes() 确认索引,对高频查询字段 createIndex;改用 explain("executionStats") 看是否走 IXSCAN。
现象updateMany 后部分字段被覆盖成了 null。
原因替换语义与更新语义混用,整对象赋值会丢掉未提及字段。
处置始终配合 $set 只写要改的字段;$set 之外的键不会被删除。
现象用 $in 查询数组字段时结果不符合预期。
原因$in 对数组字段是「包含任一元素即命中」,而不是逐个元素精确匹配。
处置需要数组包含全部元素时用 $all;需要精确匹配用字段值直接写。
现象插入时出现 duplicate key error,但数据里明明没有重复值。
原因已存在唯一索引,且重复判定按索引字段而非 _id。
处置用 getIndexes() 找出 unique 索引并检查其字段的实际取值;索引建错字段也会误报。
现象集合数据量暴涨,磁盘被占满。
原因未设置 TTL 索引,日志类文档永久保留。
处置对时间字段建 expireAfterSeconds 索引;用 db.stats() 确认实际占用。
现象聚合管道跑得很慢,内存溢出报错。
原因$sort 与 $group 在大集合上产生大量内存占用,且 allowDiskUse 未开。
处置把 $match 放到管道最前缩小数据量;必要时 allowDiskUse: true;确认排序字段有索引。
现象use 一个不存在的库后,它出现在 show dbs 里。
原因use 对不存在的库会立即创建。
处置误建后用 db.dropDatabase() 删除;只想查看库列表不要 use 不存在的名字。
排障路径
1看查询到底有没有走索引
db.collection.find({age: {$gt: 18}}).explain("executionStats")关注 winningPlan 里是 IXSCAN 还是 COLLSCAN,以及 totalDocsExamined。
2确认集合的索引
db.collection.getIndexes()排查慢查询第一步:查询字段是否已建索引、索引是否唯一。
3按字段分组统计
db.collection.aggregate([{$group: {_id: "$city", n: {$sum: 1}}}])$match 放在管道最前可显著减少参与 $group 的数据量。
4用 TTL 索引自动清理过期数据
db.logs.createIndex({createdAt: 1}, {expireAfterSeconds: 2592000})expireAfterSeconds 单位为秒;字段必须是 BSON Date 类型。
5确认数据库实际占用
db.stats()含 dataSize 与 indexSize,定位磁盘占用是数据还是索引。
命令示例
先建索引再查询,否则数据一多就慢
db.orders.createIndex({ customerId: 1, createdAt: -1 })
db.orders.find({ customerId: 'c_1024' }).sort({ createdAt: -1 }).limit(20)复合索引遵循最左前缀:只有以 customerId 开头的条件能命中。字段顺序按实际查询模式排,常查字段放前面。
输出
createdAt_-1_customerId_1
{ "customerId" : 1, "createdAt" : -1 }
{ "orderId" : "o_8821", "total" : 199.0 }聚合管道:$match 放最前
db.orders.aggregate([
{ $match: { status: "paid", createdAt: { $gte: ISODate("2026-09-01") } } },
{ $group: { _id: "$customerId", total: { $sum: "$amount" }, n: { $sum: 1 } } },
{ $sort: { total: -1 } },
{ $limit: 10 }
])管道按顺序执行,$match 放最前先把数据量缩小,后续 $group/$sort 的开销随之下降。这是聚合性能最关键的一条。
输出
{ "_id" : "c_1024", "total" : 1842.5, "n" : 12 }
{ "_id" : "c_2087", "total" : 1204.0, "n" : 7 }TTL 索引自动清理过期数据
db.sessions.createIndex({ createdAt: 1 }, { expireAfterSeconds: 3600 })适合日志与会话,过期后 MongoDB 自动删除文档,省掉清理任务。注意它是后台周期执行,删除有延迟而非准点发生。
输出
createdAt_1
常见坑与注意事项
- 不建索引的查询是全集合扫描,数据量一大立刻变慢;上线前先确认筛选字段的索引存在。
- 复合索引遵循最左前缀,字段顺序按实际查询模式决定,放错顺序等于没建。
- db.collection.remove() 等旧 API 已废弃,使用 deleteMany / deleteOne。
- TTL 索引删除是异步的,文档过期后不会立刻消失,不能依赖它做精确时点清理。
- estimatedDocumentCount 读元数据很快但事务未提交时可能不准,要求精确用 countDocuments。
- 对无索引字段排序并 skip 大量记录(如 skip 100000)会退化为全量扫描,改用游标分页。
提示
- MongoDB 默认不限制 schema,但建议用 Mongoose 等 ORM 做数据校验。
- 查询时避免全表扫描,大集合务必建索引,用 explain() 查看执行计划。
- 复制集至少 3 个节点保证高可用,奇数节点避免脑裂。
常见问题
MongoDB 查询变慢应该先做什么?
先确认筛选字段是否建了索引,用 db.collection.getIndexes() 查看现有索引。文档型数据库的灵活-schema 是有代价的:不建索引的查询就是全集合扫描,数据量一大立刻变慢。复合索引遵循最左前缀原则,db.collection.createIndex({f1: 1, f2: 1}) 只能加速以 f1 开头的查询条件,字段顺序要按实际查询模式安排。
TTL 索引是做什么的?
db.collection.createIndex({field: 1}, {expireAfterSeconds: 3600}) 会为该字段建一个过期索引,字段值若是日期或时间戳,过期后 MongoDB 会自动删除该文档。典型场景是日志和会话:给 created_at 建 TTL 索引就能自动清理,不用另写清理任务。注意它是后台周期执行的,删除有延迟,不是准点发生。
countDocuments 和 estimatedDocumentCount 有什么区别?
estimatedDocumentCount 读取集合统计信息,速度极快但对未完成的事务写入可能不准;countDocuments 实际扫描并精确统计,慢但结果可靠。要求准确时用 countDocuments,只是想知道大概数量时用 estimatedDocumentCount。批处理脚本里通常两者都要——先用估算判断要不要继续,再用精确值做最终校验。
聚合管道和普通查询该怎么选?
简单筛选和排序用 find 即可,索引能直接生效。涉及分组统计、多字段变换或跨阶段处理时用 aggregate,它按顺序执行 $match、$group、$project、$sort、$limit 等阶段。关键点是尽量把 $match 放在最前面先缩小数据量,这样后续阶段处理的数据更少、速度更快。
TTL 索引和普通索引有什么区别?
普通索引只加速查找,TTL 索引除了加速按时间字段查询,还会在文档过期后自动删除它,相当于把数据清理交给数据库本身。唯一索引则保证字段值不重复,配合 {unique: true} 创建。三者可以组合使用,比如既唯一又会过期的会话记录。
由 巧匠 维护
公开更新于 2026年7月21日,内容持续校对官方文档。