尧图精选

MongoDB常用命令实战:从库表操作到索引聚合与安全运维

🕒 发布时间:2026/9/18 11:40:08 📁 来源:尧图网络
装完MongoDB第一件事是什么很多人习惯点开可视化工具连上看一眼但我在实际排障时发现真正能救命的往往是命令行。数据库连不上、写入变慢、磁盘快满、查询走了全表扫描……这些问题进了图形界面反而不好定位还是在命令行里敲几个命令来得直接。MongoDB的常用命令说多不多说少不少但是把这些基础命令理清楚对日常开发、运维、面试都有实打实的价值。这篇文章我会从最常用的库和集合操作讲起再到文档增删改查、查询排序、索引、聚合最后补上备份恢复和安全排查这些运维必用命令。每一类命令我都给了实际场景和踩坑提醒照着敲一遍基本就能上手。适合刚接触MongoDB的开发者也适合后端或运维同学拿来当速查手册。1. 整体设计与思路拆解为什么绕不开命令行1.1 命令行才是MongoDB的第一手工具MongoDB 进入 4.x 之后官方把内置的 shell 逐渐迁移到了mongosh老版的mongo命令虽然还能用但新特性支持上已经明显落后。我记得最早用mongo连一个 4.4 实例时想试一下新的聚合阶段竟然不支持后来换了mongosh才顺畅。很多人在 Windows 上装好 MongoDB服务也启动了结果打开控制台敲mongo发现命令找不到第一反应是安装失败。其实多半是环境变量没配好或者装的是新版只带mongosh。如果你也遇到这个问题先别急着重装看下安装目录里的 bin 文件夹一般有两个可执行文件mongod服务端进程启动数据库实例用。mongosh客户端 shell连接操作数据库用。提示Windows 上如果在命令行直接敲mongod报“不是内部或外部命令”就是环境变量 PATH 没加对。把 MongoDB 安装目录下的 bin 路径加进去重新开一个终端就好。1.2 MongoDB命令体系的脉络MongoDB 的数据模型是“库 → 集合 → 文档”的三层结构所以命令也顺着这个逻辑分层数据库层查看、创建、切换、删除数据库。集合层创建、查看、重命名、删除集合。文档层插入、查询、更新、删除文档。索引与聚合优化查询、批量统计。运维管理连接状态、服务信息、备份恢复。理解了这条脉络记命令就变得有规律了。用 SQL 来类比库对应 database集合对应 table文档对应 row但 MongoDB 的文档是灵活结构的 JSON 对象不需要预先定义字段。这也是它和关系型数据库最不一样的地方。1.3 环境准备与工具选择工欲善其事必先利其器。我建议本地至少准备两个环境一个完整的 MongoDB 服务端社区版即可4.4 或更高都行。一个顺手的客户端工具比如 MongoDB Compass 或 Studio 3T日常可视化管理用。但请注意图形化工具能帮你“看”却不能帮你“查问题”。真正遇到连接数暴涨、慢查询、索引失效时还是要靠命令行输出explain()、serverStatus()这些关键信息。所以重点还是把命令行基础打牢工具反而不用太依赖。2. 核心细节解析与实操要点从库到集合再到文档2.1 数据库级操作use、db、show dbs、dropDatabaseMongoDB 的数据库操作很简单核心就几个命令。// 查看当前连接的库 db // 查看所有数据库有数据的才会显示 show dbs // 切换或创建数据库 use mydb // 删除当前数据库 db.dropDatabase()这里藏着一个新手最容易踩的坑use看起来是切换数据库但如果你use一个不存在的库MongoDB 并不会马上创建它。只有往这个库里写入第一条数据比如插入一个文档或创建集合之后数据库才会真正落盘。所以你执行use newdb后再show dbs发现 newdb 不在列表里是正常的不是安装有问题。dropDatabase()是个危险操作它会删除当前所在库里的全部数据而且没有确认弹窗。我一般会在生产环境禁用这个命令的权限只留审计专用的账号。如果你只是想清掉某个业务库再重建建议先用db.stats()看看库大小确认没误连。2.2 集合级操作createCollection、show collections、renameCollection、drop集合相当于关系型数据库的表但不需要在建表时定义字段结构。来看常用命令// 查看当前库下所有集合 show collections // 显式创建集合通常在插入第一条文档时也会自动创建 db.createCollection(users) // 给集合加一个固定大小的限制capped collection常用于日志类场景 db.createCollection(logs, { capped: true, size: 1048576, max: 5000 }) // 重命名集合 db.users.renameCollection(members) // 删除集合注意整个集合连带索引一起删掉 db.members.drop()capped集合比较有意思它有点像“环形队列”满了以后会自动覆盖旧数据非常适合日志、消息流的场景。但注意capped集合不能调用删除文档的普通方法deleteMany等只能整个集合 drop这个特性在选型时要考虑清楚。2.3 文档CRUDinsert、find、update、delete文档操作是日常最高频的部分。我用一个 user 集合来演示。插入文档// 插入单条 db.users.insertOne({ name: 张三, age: 28, city: 北京 }) // 批量插入 db.users.insertMany([ { name: 李四, age: 24, city: 上海 }, { name: 王五, age: 32, city: 广州 } ])insertOne和insertMany都会自动生成_id字段。如果文档本身带了_idMongoDB 会以你传入的为准。注意很多旧教程会写db.users.insert(...)新版本里insert被拆分为insertOne/insertMany。虽然insert仍然可用但不建议在新代码里用语义不清晰而且批量插入的校验行为和insertMany有差异。查询文档// 查询全部 db.users.find() // 美化输出 db.users.find().pretty() // 按条件查询 db.users.find({ city: 北京 }) // 查询单条 db.users.findOne({ name: 张三 })find()返回的是一个游标cursor不是你想象的“结果数组”。在 shell 里它会自动打印前 20 条然后输入it继续迭代。如果文档数特别多直接查全量会把服务端内存打满生产环境一定要加条件或分页。更新文档// 更新匹配到的第一个文档 db.users.updateOne( { name: 张三 }, { $set: { age: 29 } } ) // 更新所有匹配到的文档 db.users.updateMany( { city: 北京 }, { $inc: { age: 1 } } ) // 替换整个文档注意第二个参数直接写新文档不是操作符 db.users.replaceOne( { name: 张三 }, { name: 张三, age: 29, city: 北京, tags: [vip] } )这里十分关键的一点很多人第一次写更新时会这样做db.users.updateOne({ name: 张三 }, { age: 29 })结果 MongoDB 直接把整个文档覆盖成了一个{ age: 29 }name字段没了。因为 update 的第二个参数如果不带$操作符会被当作“要替换的完整文档”处理。这个坑在面试里也经常出现要特别小心。删除文档// 删除匹配到的第一个文档 db.users.deleteOne({ name: 张三 }) // 删除所有匹配到的文档 db.users.deleteMany({ city: 上海 }) // 清空集合索引保留但比 drop 慢 db.users.deleteMany({})删除操作在生产环境要谨慎建议先find走一遍条件再countDocuments确认条数最后才执行删除。这个习惯能避免很多事故。2.4 update操作符的细节补充更新操作里最常用的操作符是$set、$unset、$inc、$push、$addToSet、$pull每个都有特定用途$set设置字段值字段不存在会自动新增。$unset删除字段。$inc给数字字段加减支持正负值。$push往数组字段尾部追加元素。$addToSet往数组字段追加元素但要求元素不重复。$pull从数组字段中删除匹配条件的元素。看一个综合案例db.users.updateOne( { name: 王五 }, { $set: { city: 深圳 }, $unset: { oldCity: }, $inc: { loginCount: 1 }, $push: { hobbies: 摄影 }, $addToSet: { tags: new-user } } )多个操作符可以在一次 update 中组合执行MongoDB 会在一趟操作里完成性能比分开执行好很多。3. 实操过程与核心环节实现查询、索引与聚合3.1 查询进阶条件运算符与正则find()里除了支持精确匹配还能用条件运算符。举个订单查询的例子// 年龄大于30 db.users.find({ age: { $gt: 30 } }) // 年龄在25到30之间 db.users.find({ age: { $gte: 25, $lte: 30 } }) // 城市在给定列表内 db.users.find({ city: { $in: [北京, 上海] } }) // 字段存在且不为 null db.users.find({ email: { $exists: true, $ne: null } }) // 正则模糊匹配类似 SQL 的 LIKE db.users.find({ name: { $regex: ^张, $options: i } })$options: i表示忽略大小写这个正则匹配在字段没有索引时会全集合扫描数据量大的时候要慎用。还有$where运算符允许写 JavaScript 表达式db.users.find({ $where: this.age 18 this.city 北京 })但这个在早期版本里有性能和安全风险现在的建议是能用查询运算符表达的尽量别用$where。我用它只干过一种事排查文档里某个字段被写成了字符串数字例如28用类型转换对比找出来的。3.2 排序、投影与分页查询结果三个常用修饰sort、projection、skip/limit。// 按年龄升序相同年龄按名字降序 db.users.find().sort({ age: 1, name: -1 }) // 只看 name 和 city 字段不显示 _id db.users.find({}, { name: 1, city: 1, _id: 0 }) // 分页跳过前10条取10条 db.users.find().sort({ age: 1 }).skip(10).limit(10)分页这里有个常见性能误区skip越深越慢因为数据库得一条条跳过前面的文档。如果分页到第 10000 页这个查询基本废了。大数据量分页更优的方案是用“上一页最后一条的排序字段”作为查询条件俗称游标分页// 上一页最后一条 age30name王五 db.users.find({ $or: [ { age: { $gt: 30 } }, { age: 30, name: { $gt: 王五 } } ] }).sort({ age: 1, name: 1 }).limit(10)游标分页在海量数据下的稳定性远好于skip这是很多 MongoDB 高并发项目的实践结论。3.3 索引策略滴滴、摩拜都在用的性能关键热词里提到“滴滴、摩拜都在用的索引”确实MongoDB 的查询性能很大程度上取决于索引设计。没有索引的查询会全集合扫描数据量一旦到了百万级别速度会断崖式下降。看一组合适的索引命令// 创建普通单字段索引 db.users.createIndex({ city: 1 }) // 创建复合索引 db.users.createIndex({ city: 1, age: -1 }) // 查看索引 db.users.getIndexes() // 删除索引 db.users.dropIndex({ city: 1 }) // 全量删除非 _id 索引 db.users.dropIndexes()索引方向1 升序、-1 降序对单字段查询影响不大但对复合索引的排序场景有明显影响。比如最常用的查询条件是{ city: 北京 }并按age倒序那索引建{ city: 1, age: -1 }比{ city: 1, age: 1 }效率更高。还有几个非常好用的索引类型唯一索引db.users.createIndex({ email: 1 }, { unique: true })防止重复数据。多键索引字段是数组时自动创建的索引适合标签、分类等场景。文本索引db.articles.createIndex({ content: text })中文分词支持有限谨慎用。TTL 索引db.logs.createIndex({ createdAt: 1 }, { expireAfterSeconds: 86400 })数据自动过期很适合日志/验证码表。索引不是越多越好索引写放大很严重。每建一个索引写入时都要同步更新索引树所以写多读少的集合要控制索引数量。我通常一个集合保持 3-5 个核心索引再多就要评估收益了。3.4 聚合管道常用统计命令的进阶用法聚合是 MongoDB 里非常强大也容易劝退的部分。它和 SQL 的GROUP BY、JOIN对标但用的是管道式写法。最常见的统计场景是“按城市统计用户数量”db.users.aggregate([ { $match: { age: { $gte: 18 } } }, { $group: { _id: $city, count: { $sum: 1 } } }, { $sort: { count: -1 } }, { $limit: 10 } ])这个管道的执行顺序是$match先过滤出符合条件的文档相当于 WHERE。$group按城市分组并计算计数相当于 GROUP BY COUNT。$sort按计数倒序排序。$limit只取前 10 名。$group里还可以做其他聚合操作比如求平均年龄、最大值、累加数组db.users.aggregate([ { $group: { _id: $city, avgAge: { $avg: $age }, maxAge: { $max: $age }, names: { $push: $name } }} ])如果需要关联两个集合可以用$lookupdb.orders.aggregate([ { $lookup: { from: users, localField: userId, foreignField: _id, as: userInfo }}, { $unwind: $userInfo } ])$lookup类似 SQL 里的LEFT JOIN但在性能上远没有关系型数据库的 join 优化成熟能用冗余字段解决的尽量不要用$lookup。这是一个从业多年的经验教训MongoDB 设计上鼓励“按查询建模”别把关系数据库的范式思维硬套进来。4. 常见问题与排查技巧实录4.1 安装失败的常见问题Windows 环境篇从热搜词就能看出来MongoDB 安装失败是很多人入门的第一道坎。我在 Windows 上装过很多次最常见的失败原因就这几类问题1服务启动失败安装 MongoDB Community Server 后如果服务起不来第一步看 Windows 事件查看器里的 MongoDB 日志十有八九是数据目录不存在或权限不足。启动前要手动创建数据目录C:\data\db和日志目录C:\data\log。问题2端口被占用MongoDB 默认端口 27017。可以用netstat -ano | findstr 27017查看端口占用如果被其他程序占用可以改用自定义端口启动mongod --port 27018 --dbpath C:\data\db问题3mongod 一闪而过在 cmd 里敲mongod服务进程一闪而过通常是因为它启动失败后在日志里写了错误但窗口关闭太快。这时候不要直接双击用命令行前台启动看输出mongod --dbpath C:\data\db --logpath C:\data\log\mongod.log然后在另一个窗口查看日志文件就能看到具体报错。问题4下载版本太新电脑带不动MongoDB 新版对硬件和系统有要求老机器跑 6.0 以上会比较吃力。如果只是学习完全可以用 4.4.30 这个版本很多热词也提到了这个版本号它稳定、资料多、兼容性好。4.2 未授权访问排查与安全加固热词里“mongodb未授权访问漏洞”是真实存在的高发问题。MongoDB 老版本默认不开启认证一旦端口暴露到公网等于把数据库大门敞开。排查方法很简单// 查看当前实例是否开了认证 db.serverStatus().security返回{ authorization: disabled }说明没开认证赶紧处理。安全加固三板斧修改配置文件mongod.conf将bindIp从0.0.0.0改为内网 IP 或127.0.0.1。开启认证。先在无认证状态创建管理员用户use admin db.createUser({ user: admin, pwd: 强密码, roles: [{ role: root, db: admin }] })然后在mongod.conf里加auth: true并重启服务。定期用show dbs检查有没有异常数据库用db.adminCommand({ listDatabases: 1 })列出所有库。4.3 慢查询定位与 explain 解读命令敲多了会发现explain()是调优的核心工具。用它会返回这条查询的执行计划重点看三个指标planStage执行节点类型COLLSCAN是全表扫描IXSCAN是走索引。docsExamined扫描了多少文档。nReturned实际返回多少文档。例子db.users.find({ city: 北京, age: { $gt: 20 } }).explain(executionStats)如果看到docsExamined几百万但nReturned只有几十基本就是索引没建好。还有一个特别容易忽略的点sort操作如果没走索引执行计划里会出现SORT阶段内存排序超过 100MB 会报错。解决办法就是创建复合索引让排序直接走索引避免内存排序。检查系统是否有慢查询可以开数据库分析器db.setProfilingLevel(1, 200) // 记录超过 200ms 的操作然后查db.system.profile.find()看慢操作详情。生产环境建议只开几分钟长期开对性能有损耗。4.4 备份与恢复mongodump/mongorestore 实战线上数据库一定要有备份习惯。最朴素的备份方式是用mongodump和mongorestore。我通常在凌晨低峰期做全量备份保留最近 7 天。# 全量备份 mongodump --host 127.0.0.1 --port 27017 --out /backup/mongo/$(date %Y%m%d) # 只备份某个库 mongodump --db mydb --out /backup/mongo/$(date %Y%m%d) # 只备份某个集合 mongodump --db mydb --collection users --out /backup/mongo/$(date %Y%m%d) # 恢复整个备份 mongorestore --drop /backup/mongo/$(date %Y%m%d) # 恢复某个库 mongorestore --db mydb --drop /backup/mongo/$(date %Y%m%d)/mydb--drop表示恢复前先删除目标集合避免新老数据混在一起。但如果目标库里正在跑业务执行--drop前最好确认业务窗口。备份文件是目录结构按 “备份根目录/库名/集合名.bson” 存放。要直接查看备份数据可以用bsondump工具先导成 JSONbsondump users.bson users.json注意mongodump 备份期间会产生读压力大集合备份时不建议在业务高峰执行。如果数据量极大可以考虑文件系统快照方式备份但配置文件和数据目录必须放在同一快照中。4.5 数据分析中的经典“坑”与应对排查问题时我总结过几个高频出现的坑值得单独列一下。坑1count 数据不准的问题db.users.count()在分片集群或大结果集下可能不准确官方建议用db.users.countDocuments({})后者内部会做聚合操作结果更可靠。坑2find().limit(0)和游标超时limit(0)表示不限制数量如果结果集很大游标会在 10 分钟后超时。处理办法是设置batchSize或用allowDiskUse对聚合开启磁盘临时存储db.users.find().batchSize(1000)坑3类型不一致导致索引失效比如age字段有的存成了数字 28有的存成了字符串28这时候走索引可能出现意外排除。检查办法db.users.find({ age: { $type: string } }).count() db.users.find({ age: { $type: int } }).count()发现数量不均就要考虑用$convert做数据清洗db.users.aggregate([ { $addFields: { ageNum: { $toInt: $age } } } ])坑4忘记给日期字段建 TTL 索引日志集合、验证码集合如果只靠定时任务删除总会有漏网之鱼。TTL 索引是天然的“自动清理工”提前设置好少写几十行删除逻辑。5. 到底怎么记命令才牢靠很多人问过我MongoDB 命令这么多怎么记得住我的方法是按场景记而不是按命令记。看到“查一查”立刻想到find()和explain()看到“改字段”立刻想到updateOne加$set看到“统计报表”立刻想到aggregate。把命令揉进真实业务场景里比死记硬背管用得多。日常运维时我还会写个小脚本用db.serverStatus()把连接数、opcounters、mem 信息定期打印出来哪一项指标不对劲一目了然。这种做法不需要额外监控平台命令行就能搞定。如果你刚开始接触 MongoDB我建议从安装一个 4.4.30 的社区版开始照着这篇文章的命令敲一遍把自己最喜欢用的命令整理成一个速查笔记。命令这件事关键不在背而在反复用。用着用着你会发现自己已经不需要看文档了。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →