MongoDB 面试
本页只放 MongoDB 面试标准回答和追问方向。文档设计、查询执行、索引、聚合、副本集、分片、事务和排查的详细原理,统一跳转到知识点页学习。
MongoDB 应该怎么从零学到生产级
text
MongoDB 不能只学增删改查,要按文档模型、嵌入和引用、索引设计、查询执行计划、聚合管道、副本集、分片、事务边界和线上排查这条链路学习。它的核心是按查询模式设计文档和索引,而不是随便存 JSON。原理:MongoDB 从零到生产级掌握,验收:MongoDB 从零到精通验收清单,项目落地:MongoDB 商业场景训练营。
怎么判断 MongoDB 是否真正学懂
text
不能只会 insertOne、find、updateOne。真正学懂要能从 BSON、文档模型、嵌入和引用、查询执行、explain、复合索引、ESR、多键索引、聚合管道、副本集、oplog、读写关注、分片键、事务边界和生产排查一路讲下来,并能说明每个环节为什么这样设计、不这样会出什么生产问题。MongoDB 适合什么场景
text
MongoDB 适合文档天然聚合、字段结构变化较快、嵌套数据较多、读写吞吐要求较高的场景,例如商品详情、用户画像、内容草稿、日志事件、资产扩展属性等。它不适合大量复杂关联、强事务和高度规范化的核心交易场景。MongoDB 不是随便存 JSON,仍然要根据查询模式设计文档结构和索引。原理:MongoDB 总览、核心全过程原理、商业场景训练营。
MongoDB 文档怎么设计
text
MongoDB 文档设计要从查询模式出发。经常一起读取、生命周期接近、数量有限的数据适合嵌入同一文档;不经常一起读取、会无限增长、生命周期不同的数据应该拆成集合引用。比如用户地址可以嵌入用户文档,但用户所有订单不适合无限追加到用户文档数组中。高频固定字段放顶层,灵活扩展字段可以放嵌套对象。原理:核心全过程原理、MongoDB 基础、文档建模决策流程。
MongoDB 查询怎么执行
text
MongoDB 查询由 Driver 发送到 mongod,mongod 解析 filter、projection、sort、limit 后由查询优化器选择执行计划。有合适索引时走 IXSCAN,再 FETCH 文档;没有合适索引时可能 COLLSCAN 扫描集合。排查时看 explain("executionStats"),重点关注 winningPlan、totalKeysExamined、totalDocsExamined、nReturned 和是否出现 COLLSCAN 或大范围 SORT。MongoDB 复合索引怎么设计
text
MongoDB 索引要从查询模式出发,而不是看到字段就加。复合索引通常把高频等值过滤字段放前面,再放范围字段或排序字段。例如查询 ownerId、status 并按 createdAt 倒序,可以考虑 { ownerId: 1, status: 1, createdAt: -1 }。设计后要用 explain 验证 totalKeysExamined 和 totalDocsExamined 是否接近返回数量。MongoDB 副本集和分片区别
text
副本集解决高可用和数据冗余,一个 Primary 接收写入,Secondary 复制 oplog 并重放,Primary 故障后选举新的 Primary。分片解决单机容量和吞吐瓶颈,通过 shard key 把数据分布到多个 shard,mongos 根据路由表转发请求。副本集关注可用性,分片关注水平扩展;分片键选错会导致数据倾斜、写热点或查询广播。原理:核心全过程原理、核心全过程原理、MongoDB 高级。
MongoDB 聚合管道怎么优化
text
聚合管道是一段一段处理文档流。优化原则是尽早用 $match 减少文档数量,尽早用 $project 裁剪字段,再做 $group、$sort、$lookup 等重操作。大集合排序要尽量利用索引,$lookup 要控制关联规模并保证关联字段有索引。复杂报表不要每次实时扫全量,可以考虑预聚合。MongoDB 事务能不能随便用
text
MongoDB 支持多文档事务,但不应该把它当成关系库随便做复杂大事务。MongoDB 的建模目标是通过文档聚合减少跨文档事务需求。事务适合少量文档、短时间、明确业务边界的强一致修改;大批量长事务、跨大量分片事务会带来延迟和资源占用,复杂强关系业务可能更适合关系型数据库。原理:核心全过程原理。
MongoDB 和 MySQL 最大区别是什么
text
MongoDB 是文档型数据库,按文档聚合保存数据,适合字段结构变化快、嵌套数据多、经常按整体读取的场景;MySQL 是关系型数据库,强调表结构、约束、Join 和事务。MongoDB 设计时要从查询模式出发,决定嵌入还是引用;MySQL 设计时更强调规范化、主外键关系和事务一致性。MongoDB 不是随便存 JSON,MySQL 也不是只能做简单 CRUD。追问:
- 什么场景适合 MongoDB?
- 什么场景不适合 MongoDB?
- 文档模型为什么要按查询模式设计?
BSON 是什么
text
BSON 是 MongoDB 底层使用的二进制文档格式。MongoDB 文档看起来像 JSON,但 BSON 支持更多类型,例如 ObjectId、Date、Decimal128、二进制等。应用对象会由 Driver 转成 BSON 写入 mongod,查询时再解码为对象。因此时间、金额、ObjectId 等不要全部当字符串存,要使用驱动支持的正确类型。追问:
- MongoDB 存的是 JSON 字符串吗?
- ObjectId 和普通字符串 ID 有什么区别?
- 为什么时间字段不要随便存字符串?
原理:MongoDB 基础:BSON。
ObjectId 怎么理解
text
ObjectId 是 MongoDB 常见的默认 _id 类型,大体包含时间戳、机器/进程相关信息和计数器,因此大致趋势递增。它适合作为内部主键,但不应该直接作为对外业务编号。跨系统幂等和业务唯一性仍然要设计业务唯一键,例如 assetNo、orderNo,并建立唯一索引。追问:
- ObjectId 是否全局唯一?
- 为什么业务编号不要直接用 ObjectId?
_id有索引吗?
MongoDB 为什么不建议无限增长数组
text
MongoDB 文档适合嵌入数量有限、经常一起读取的数据。无限增长数组会让单个文档越来越大,读取、更新、网络传输和内存成本都上升,还可能触及单文档大小限制。比如用户地址适合嵌入,用户所有订单、评论、采集日志不适合无限追加到一个文档里,应该拆成独立集合并建立关联字段索引。追问:
- 用户地址为什么可以嵌入?
- 订单列表为什么不适合嵌入用户文档?
- 单个文档变大有什么问题?
原理:MongoDB 基础:嵌入还是引用、资产采集日志拆分。
$push 和 $addToSet 区别
text
$push 会把元素追加到数组中,即使数组里已经有相同值也会继续追加;$addToSet 会在数组中不存在该值时才追加,适合标签、权限码这类不希望重复的场景。两者都不应该用于无限增长数组,日志、订单、评论这类数据应拆成独立集合。追问:
- 标签去重用哪个操作符?
$addToSet能不能保证复杂对象完全按业务去重?- 数组字段建索引会发生什么?
原理:MongoDB 基础:push 和 addToSet、高级:多键索引。
MongoDB 软删除要注意什么
text
重要业务数据通常不建议直接物理删除,而是用 deleted、deletedAt 等字段软删除。软删除后所有列表和统计查询都要过滤 deleted 条件,索引也要考虑 deleted 字段。否则已删除数据可能重新出现在页面或统计中。真正需要释放空间时,可以做归档和周期清理。追问:
- 软删除后为什么查询都要带 deleted 条件?
- 软删除字段是否需要建索引?
- 什么数据可以物理删除?
原理:MongoDB 基础:删除数据。
MongoDB explain 看哪些字段
text
MongoDB 排查查询性能常用 explain("executionStats")。重点看 winningPlan 是否走 IXSCAN 还是 COLLSCAN,totalKeysExamined 扫描了多少索引项,totalDocsExamined 扫描了多少文档,nReturned 返回多少文档。如果 totalDocsExamined 远大于 nReturned,说明扫描了大量无用文档;如果出现 COLLSCAN 或大范围 SORT,就要检查索引和查询条件。追问:
- IXSCAN 和 COLLSCAN 区别是什么?
- totalDocsExamined 远大于 nReturned 说明什么?
- 排序慢怎么排查?
MongoDB 有索引为什么还可能慢
text
MongoDB 走索引不代表一定快。要看 totalKeysExamined、totalDocsExamined 和 nReturned 的比例。如果扫描大量索引项和文档只返回少量结果,说明索引选择性差或复合索引顺序不匹配;如果计划里有 SORT,说明排序没有被索引满足;如果需要 FETCH 大量原始文档,也会慢。目标不是只看到 IXSCAN,而是让扫描量接近返回量,并避免大范围排序。追问:
IXSCAN后为什么还会有FETCH?- 什么是覆盖查询?
totalKeysExamined很大说明什么?
原理:索引设计:查询有索引为什么还可能慢、索引设计:覆盖查询。
MongoDB 复合索引字段顺序怎么定
text
复合索引字段顺序要根据查询模式设计,常见思路是等值过滤字段在前,再考虑排序字段和范围字段。例如按 hospitalId、status 过滤并按 createdAt 倒序查询,可以建立 { hospitalId: 1, status: 1, createdAt: -1 }。设计后必须用 explain 验证扫描索引项和扫描文档数是否接近返回数量。追问:
- 为什么不能看到字段就建索引?
- ESR 原则是什么?
- 索引越多为什么写入越慢?
原理:MongoDB 高级:ESR原则、索引设计。
MongoDB ESR 原则是什么
text
ESR 是复合索引设计的常用思路,E 表示 Equality 等值条件,S 表示 Sort 排序字段,R 表示 Range 范围条件。比如按 hospitalId、status 等值过滤,并按 createdAt 倒序分页,可以建立 { hospitalId: 1, status: 1, createdAt: -1 }。这样先定位医院和状态,再按时间顺序取数据。ESR 不是死规则,还要结合字段区分度、查询频率和 explain 验证。追问:
- 为什么 createdAt 放最前面可能不好?
- 排序字段和范围字段同时存在怎么设计?
- ESR 为什么还要 explain 验证?
原理:索引设计:ESR原则讲清楚。
MongoDB skip 深分页为什么慢
text
skip 深分页慢,是因为数据库不是直接跳到第 N 条,而是要按索引或排序顺序扫描并丢弃前 N 条,再返回 limit 条。skip 越大,浪费越多。列表无限滚动更推荐游标分页,例如按 createdAt 和 _id 作为稳定锚点继续查询下一页。追问:
- 为什么只用 createdAt 做游标可能重复或漏数据?
- 游标分页能不能任意跳页?
- 深分页和排序索引有什么关系?
原理:索引设计:skip深分页为什么慢。
MongoDB TTL 索引适合什么
text
TTL 索引用于让文档按时间自动过期,适合验证码、临时 token、短期日志等临时数据。TTL 删除不是精确实时删除,也不适合核心业务数据。订单、资产、审计这类重要数据不能直接靠 TTL 删除,应先归档或走业务清理流程。追问:
- TTL 删除是否精确到秒?
- TTL 为什么不适合核心业务数据?
- 日志保留策略怎么设计?
原理:MongoDB 高级:TTL索引。
MongoDB 聚合管道为什么要先 match
text
聚合管道是一段一段处理文档流。越靠前的阶段处理的数据越多,所以要尽早 $match 过滤,尽早 $project 裁剪字段,再做 $group、$sort、$lookup 这类重操作。如果先 group 或 sort 全量数据,再过滤,就会放大 CPU、内存和磁盘压力。高频报表不应该每次实时扫全量,应该考虑预聚合、异步导出或数仓。追问:
$project为什么能优化聚合?$group和$sort为什么重?- 什么场景应该预聚合?
原理:聚合管道:聚合管道怎么执行、聚合管道:医疗资产按科室统计。
MongoDB $lookup 有什么风险
text
$lookup 可以做集合关联,但不能把 MongoDB 当关系库无限 Join。高频复杂 lookup 通常说明文档模型或冗余设计需要重新评估。lookup 前要先 match 缩小主集合,foreignField 要有索引,并控制返回字段。如果只是资产列表展示科室名称,且科室名称变化很少,可以考虑冗余 departmentName,避免每次实时关联。追问:
$lookup的 foreignField 为什么要建索引?- 冗余字段有什么代价?
- 什么场景更适合数仓或预聚合?
MongoDB allowDiskUse 是不是性能优化
text
allowDiskUse 允许聚合中的部分大排序、大分组把临时数据写到磁盘,能避免内存限制错误,但不是性能优化本身。磁盘临时文件通常比内存慢,也会影响整库 IO。如果接口长期依赖 allowDiskUse 才能跑完,应该考虑缩小过滤范围、补索引、预聚合、异步导出或进入数仓。追问:
- allowDiskUse 解决什么,不解决什么?
- 大聚合为什么可能打磁盘?
- 为什么高频报表不适合每次实时聚合?
MongoDB oplog 是什么
text
oplog 是复制集用于同步的操作日志。Primary 写入后把操作记录到 oplog,Secondary 拉取并重放这些操作保持数据同步。oplog 是有大小限制的循环日志,如果 Secondary 落后太久,所需 oplog 已被覆盖,就需要重新同步。复制延迟会影响读从库的数据新鲜度。追问:
- oplog 和普通业务日志有什么区别?
- Secondary 为什么会落后?
- oplog 窗口太短有什么风险?
writeConcern 怎么理解
text
writeConcern 控制写入需要达到什么确认级别。w:1 表示 Primary 写入成功即可返回,性能较好但风险更高;w:"majority" 表示多数节点确认后返回,可靠性更强;配合 j:true 可以要求写 journal。核心数据不能只看低延迟,要根据数据重要性选择合适 writeConcern。追问:
- w:1 和 majority 的区别是什么?
- writeConcern 和复制延迟有什么关系?
- 什么业务应该用更强写关注?
readPreference 有什么风险
text
readPreference 控制读请求从 Primary 还是 Secondary 读取。读 Secondary 可以分担读压力,但可能读到旧数据,因为复制存在延迟。用户刚写完马上读、订单支付状态、资产状态变更这类强实时场景通常应读 Primary 或设计读写一致策略,不能无脑读从库。追问:
- secondary 读为什么可能读到旧数据?
- 什么场景可以读从库?
- 读写分离为什么会有一致性问题?
原理:MongoDB 高级:读偏好。
shard key 怎么选
text
shard key 决定数据如何分布到不同 shard。好的 shard key 要让写入均匀、查询能带上 shard key、数据不倾斜、不产生热点。自增时间字段容易让新写入集中到一个分片;低基数字段如 status 会严重倾斜;随机字段写入均匀但范围查询差。分片前应先确认单机真的无法承载,并准备好备份、监控和运维能力。追问:
- 为什么时间递增字段可能形成写热点?
- 为什么低基数字段不适合做 shard key?
- 分片为什么不是性能问题第一解?
副本集能不能替代备份
text
不能。副本集解决节点故障和高可用,Primary 上的误删、误更新也会通过 oplog 同步到 Secondary。备份解决误删、灾难恢复和历史时间点恢复。生产环境需要副本集、备份、恢复演练和监控一起设计,不能认为有多个副本就不需要备份。追问:
- 误删数据为什么会同步到副本?
- 副本集和备份分别解决什么?
- 备份为什么必须做恢复演练?
原理:MongoDB 高级:备份和监控。
