共计 5258 个字符,预计需要花费 14 分钟才能阅读完成。
🟢 一、初级(基础概念与 CRUD)
1. MongoDB 是什么类型的数据库?
答案 :MongoDB 是一个 面向文档的 NoSQL 数据库,使用 BSON(Binary JSON)格式存储数据。
解析 :与传统关系型数据库(如 MySQL)不同,MongoDB 不使用表和行,而是使用 集合(Collection) 和 文档(Document)。文档是键值对的集合,结构灵活,支持嵌套。
2. MongoDB 中的“集合”(Collection)相当于关系型数据库中的什么?
答案 :相当于 表(Table)。
解析 :集合是文档的容器,类似于关系型数据库中的表。但集合中的文档 不要求具有相同的结构(schema-less)。
3. 如何在 MongoDB 中创建一个数据库?
答案:使用 use <database_name> 命令。如果数据库不存在,MongoDB 会在首次插入数据时自动创建它。
示例:
use mydb
db.myCollection.insertOne({name: "Alice"})
此时 mydb 数据库被真正创建。
4. 如何查看当前所有数据库?
答案:show dbs
注意:刚 use 一个新数据库但未插入数据时,show dbs 不会显示它。
5. 插入一条文档到集合 users 中,字段为 {name: "Tom", age: 25}。
答案:
db.users.insertOne({name: "Tom", age: 25})
解析:insertOne() 插入单个文档;也可用 insertMany() 插入多个。
6. 查询 users 集合中所有文档。
答案:
db.users.find()
或格式化输出:
db.users.find().pretty()
7. 查询 users 中 age 大于 20 的用户。
答案:
db.users.find({age: { $gt: 20} })
解析:$gt 是比较操作符,表示“大于”。
8. 更新 users 中 name 为 “Tom” 的用户,将其 age 改为 26。
答案:
db.users.updateOne({name: "Tom"}, {$set: { age: 26} })
注意 :必须使用 $set,否则会 替换整个文档。
9. 删除 users 中 age 小于 18 的所有用户。
答案:
db.users.deleteMany({age: { $lt: 18} })
10. MongoDB 文档的主键字段叫什么?由谁生成?
答案:字段名为 _id,默认由 MongoDB 自动生成一个 ObjectId(12 字节唯一标识)。
解析:_id 是唯一索引,不可重复。用户也可自定义 _id 值(如字符串、数字等)。
11. ObjectId 由哪几部分组成?
答案:共 12 字节,包含:
- 4 字节:时间戳(秒)
- 3 字节:机器标识
- 2 字节:进程 ID
- 3 字节:计数器
用途:可从 ObjectId 反推文档创建时间。
12. 如何查看集合 users 的索引?
答案:
db.users.getIndexes()
13. 如何为 users 集合的 name 字段创建索引?
答案:
db.users.createIndex({name: 1})
1 表示升序,-1 表示降序。
14. MongoDB 默认是否区分大小写进行字符串查询?
答案 : 是,默认区分大小写。
示例:{name: "alice"} 不会匹配 "Alice"。
解决:使用正则表达式或文本索引实现不区分大小写。
15. 如何退出 MongoDB Shell?
答案:输入 exit 或按 Ctrl + D。
🟡 二、中级(查询进阶、聚合、索引、数据建模)
16. 使用聚合管道(Aggregation Pipeline)统计 users 中每个年龄段的人数。
答案:
db.users.aggregate([
{$group: { _id: "$age", count: { $sum: 1} } }
])
解析:$group 按 age 分组,$sum: 1 表示每条文档计数 1。
17. 如何查询嵌套文档?例如文档为 {name: "Bob", address: { city: "Beijing"} },查询北京用户。
答案:
db.users.find({"address.city": "Beijing"})
注意:嵌套字段需用点号 . 引用。
18. 如何查询数组字段包含特定值?例如 tags: ["news", "tech"],查询包含 “tech” 的文档。
答案:
db.articles.find({tags: "tech"})
或使用 $in:
db.articles.find({tags: { $in: ["tech"] } })
19. $lookup 在聚合中有什么作用?
答案 :实现 左外连接(left outer join),用于关联两个集合。
示例:将 orders 与 customers 关联:
db.orders.aggregate([
{
$lookup: {
from: "customers",
localField: "customerId",
foreignField: "_id",
as: "customerInfo"
}
}
])
20. 什么是复合索引?何时使用?
答案:对多个字段创建的索引,如 {name: 1, age: -1}。
使用场景:当查询条件包含多个字段时,复合索引可大幅提升性能。
注意 :遵循 最左前缀原则。
21. 解释 db.collection.explain("executionStats") 的作用。
答案:显示查询的执行计划和性能统计,包括:
- 是否使用索引(
IXSCANvsCOLLSCAN) - 扫描文档数(
totalDocsExamined) - 返回文档数(
nReturned)
用途:用于查询优化。
22. 什么是“覆盖查询”(Covered Query)?
答案 :查询所需的所有字段都包含在索引中,MongoDB 无需回表读取文档,直接从索引返回结果。
示例:
// 索引:{name: 1, age: 1}
db.users.find({name: "Tom"}, {_id: 0, name: 1, age: 1})
此查询是覆盖查询。
23. 如何限制查询结果数量?如只取前 5 条。
答案:
db.users.find().limit(5)
24. 如何跳过前 10 条结果,用于分页?
答案:
db.users.find().skip(10).limit(10)
注意 :skip + limit 在大数据量下性能差,建议用 基于游标的分页(如 _id > lastId)。
25. 什么是 TTL 索引?如何创建?
答案:TTL(Time-To-Live)索引可自动删除过期文档,常用于日志、会话管理。
创建:
db.logs.createIndex({createdAt: 1}, {expireAfterSeconds: 3600})
文档在 createdAt 时间后 1 小时自动删除。
26. 解释 $unwind 聚合阶段的作用。
答案:将数组字段“展开”为多条文档。
示例:
// 原文档:{_id: 1, items: ["A", "B"] }
db.orders.aggregate([{ $unwind: "$items"}])
// 输出两条:{_id:1, items:"A"}, {_id:1, items:"B"}
27. 如何在更新时“upsert”(不存在则插入)?
答案:在 updateOne 或 updateMany 中设置 upsert: true。
db.users.updateOne({ name: "NewUser"},
{$set: { age: 30} },
{upsert: true}
)
28. 什么是“原子性”?MongoDB 的写操作是否原子?
答案 :MongoDB 单文档写操作是原子的,但跨文档操作不是。
建议:通过嵌入文档或事务(4.0+)保证多文档一致性。
29. 如何查看 MongoDB 版本?
答案:
db.version()
或 shell 启动时显示。
30. 解释 mongod 和 mongo 的区别。
答案:
mongod:MongoDB 数据库服务进程(daemon)mongo(旧)或mongosh(新):客户端 Shell 工具
🔴 三、高级(事务、分片、复制、性能调优、安全)
31. MongoDB 从哪个版本开始支持多文档事务?
答案 :4.0 版本(仅限副本集),4.2 版本 扩展到分片集群。
注意:事务有性能开销,应谨慎使用。
32. 如何在 MongoDB 中开启一个事务?
答案(Node.js 示例):
const session = client.startSession();
try {await session.withTransaction(async () => {await db.users.updateOne({ _id: 1}, {$inc: { balance: -100} }, {session});
await db.users.updateOne({_id: 2}, {$inc: { balance: 100} }, {session});
});
} finally {await session.endSession();
}
33. 什么是副本集(Replica Set)?作用是什么?
答案 :副本集是一组维护 相同数据集 的 MongoDB 实例,提供:
- 高可用(自动故障转移)
- 数据冗余
- 读扩展(可从 secondary 读)
组成:1 个 Primary + 多个 Secondary +(可选)Arbiter。
34. 什么是分片(Sharding)?何时需要分片?
答案 :分片是将数据 水平拆分 到多个服务器(shard)的技术。
适用场景:
- 数据量 > 单机存储容量
- 写入吞吐量 > 单机处理能力
组件:Shard、Config Server、Mongos(路由)。
35. 如何选择分片键(Shard Key)?
答案:好的分片键应满足:
- 高基数(值多样)
- 高写分布(避免热点)
- 查询常用(避免 scatter-gather)
避免:单调递增字段(如 ObjectId、时间戳)作为分片键。
36. 解释“读偏好”(Read Preference)。
答案:控制客户端从副本集的哪个节点读取数据:
primary(默认)primaryPreferredsecondarysecondaryPreferrednearest
用途:负载均衡、降低主节点压力。
37. 什么是“写关注”(Write Concern)?
答案:控制写操作的确认级别,例如:
{w: 1} // 默认,主节点确认
{w: "majority"} // 大多数副本确认
{j: true} // 写入日志(journal)
权衡:更高的写关注 = 更强一致性,但更低性能。
38. 如何备份 MongoDB 数据?
答案:常用方法:
mongodump/mongorestore(逻辑备份)- 文件系统快照(需启用 journal)
- Ops Manager / Cloud Manager(企业级)
示例:
mongodump --db mydb --out /backup/
39. 什么是“oplog”?它在副本集中起什么作用?
答案 :oplog(operations log)是一个 固定集合,记录所有数据修改操作。
作用 :Secondary 节点通过 复制 oplog 来同步 Primary 的数据变更。
40. 如何监控 MongoDB 性能?
答案:工具包括:
db.currentOp():查看当前操作db.killOp():终止慢查询- MongoDB Atlas / Ops Manager(可视化)
- Prometheus + MongoDB Exporter
41. 解释“存储引擎”(Storage Engine)。MongoDB 默认使用哪个?
答案:存储引擎管理数据在磁盘上的存储方式。
- WiredTiger(默认,3.2+):支持文档级并发、压缩、事务
- MMAPv1(旧版,已弃用)
42. 如何启用 MongoDB 认证(Authentication)?
答案:
- 启动 mongod 时添加
--auth - 创建管理员用户:
use admin
db.createUser({user: "admin", pwd: "123456", roles: ["root"] })
- 客户端连接时使用
-u-p参数。
43. 什么是“角色”(Role)?列举几个内置角色。
答案:角色定义用户权限。内置角色包括:
read/readWrite(数据库级)dbAdmin(管理集合)userAdmin(管理用户)root(超级用户)
44. 如何优化一个慢查询?
答案:步骤:
- 使用
explain("executionStats")分析 - 检查是否全表扫描(COLLSCAN)
- 为查询字段添加合适索引
- 避免
$where、$regex(非前缀) - 考虑数据模型重构(如嵌入 vs 引用)
45. MongoDB 是否支持 JOIN?如何实现多表关联?
答案 :MongoDB 不支持 SQL 式 JOIN,但可通过以下方式实现关联:
- 嵌入文档(Embedding):适合一对少、数据不常变
- 引用 ID(Referencing)+ 应用层多次查询
- 聚合
$lookup:适合偶尔关联,性能低于嵌入
原则 : 以读写模式驱动数据建模,而非范式。
✅ 总结
| 难度 | 题数 | 覆盖知识点 |
|---|---|---|
| 初级 | 15 | 基础概念、CRUD、索引、ObjectId |
| 中级 | 15 | 聚合、嵌套查询、复合索引、分页、TTL、upsert |
| 高级 | 15 | 事务、副本集、分片、安全、性能调优、备份 |
💡 建议:
- 初学者先掌握初级 + 中级
- 面试 / 生产环境需重点掌握高级部分(尤其事务、分片、性能)
- 动手实践:使用 MongoDB Atlas 免费集群练习

