Skip to content

MongoDB 面试

本页只放 MongoDB 面试标准回答和追问方向。文档设计、查询执行、索引、聚合、副本集、分片、事务和排查的详细原理,统一跳转到知识点页学习。

MongoDB 应该怎么从零学到生产级

text
MongoDB 不能只学增删改查,要按文档模型、嵌入和引用、索引设计、查询执行计划、聚合管道、副本集、分片、事务边界和线上排查这条链路学习。它的核心是按查询模式设计文档和索引,而不是随便存 JSON。

原理:MongoDB 从零到生产级掌握,验收:MongoDB 从零到精通验收清单,项目落地:MongoDB 商业场景训练营

怎么判断 MongoDB 是否真正学懂

text
不能只会 insertOne、find、updateOne。真正学懂要能从 BSON、文档模型、嵌入和引用、查询执行、explain、复合索引、ESR、多键索引、聚合管道、副本集、oplog、读写关注、分片键、事务边界和生产排查一路讲下来,并能说明每个环节为什么这样设计、不这样会出什么生产问题。

原理:MongoDB 从零到精通验收清单

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。

追问:

  1. 什么场景适合 MongoDB?
  2. 什么场景不适合 MongoDB?
  3. 文档模型为什么要按查询模式设计?

原理:MongoDB 基础MongoDB 和关系库差异

BSON 是什么

text
BSON 是 MongoDB 底层使用的二进制文档格式。MongoDB 文档看起来像 JSON,但 BSON 支持更多类型,例如 ObjectId、Date、Decimal128、二进制等。应用对象会由 Driver 转成 BSON 写入 mongod,查询时再解码为对象。因此时间、金额、ObjectId 等不要全部当字符串存,要使用驱动支持的正确类型。

追问:

  1. MongoDB 存的是 JSON 字符串吗?
  2. ObjectId 和普通字符串 ID 有什么区别?
  3. 为什么时间字段不要随便存字符串?

原理:MongoDB 基础:BSON

ObjectId 怎么理解

text
ObjectId 是 MongoDB 常见的默认 _id 类型,大体包含时间戳、机器/进程相关信息和计数器,因此大致趋势递增。它适合作为内部主键,但不应该直接作为对外业务编号。跨系统幂等和业务唯一性仍然要设计业务唯一键,例如 assetNo、orderNo,并建立唯一索引。

追问:

  1. ObjectId 是否全局唯一?
  2. 为什么业务编号不要直接用 ObjectId?
  3. _id 有索引吗?

原理:MongoDB 基础:ObjectId

MongoDB 为什么不建议无限增长数组

text
MongoDB 文档适合嵌入数量有限、经常一起读取的数据。无限增长数组会让单个文档越来越大,读取、更新、网络传输和内存成本都上升,还可能触及单文档大小限制。比如用户地址适合嵌入,用户所有订单、评论、采集日志不适合无限追加到一个文档里,应该拆成独立集合并建立关联字段索引。

追问:

  1. 用户地址为什么可以嵌入?
  2. 订单列表为什么不适合嵌入用户文档?
  3. 单个文档变大有什么问题?

原理:MongoDB 基础:嵌入还是引用资产采集日志拆分

$push$addToSet 区别

text
$push 会把元素追加到数组中,即使数组里已经有相同值也会继续追加;$addToSet 会在数组中不存在该值时才追加,适合标签、权限码这类不希望重复的场景。两者都不应该用于无限增长数组,日志、订单、评论这类数据应拆成独立集合。

追问:

  1. 标签去重用哪个操作符?
  2. $addToSet 能不能保证复杂对象完全按业务去重?
  3. 数组字段建索引会发生什么?

原理:MongoDB 基础:push 和 addToSet高级:多键索引

MongoDB 软删除要注意什么

text
重要业务数据通常不建议直接物理删除,而是用 deleted、deletedAt 等字段软删除。软删除后所有列表和统计查询都要过滤 deleted 条件,索引也要考虑 deleted 字段。否则已删除数据可能重新出现在页面或统计中。真正需要释放空间时,可以做归档和周期清理。

追问:

  1. 软删除后为什么查询都要带 deleted 条件?
  2. 软删除字段是否需要建索引?
  3. 什么数据可以物理删除?

原理:MongoDB 基础:删除数据

MongoDB explain 看哪些字段

text
MongoDB 排查查询性能常用 explain("executionStats")。重点看 winningPlan 是否走 IXSCAN 还是 COLLSCAN,totalKeysExamined 扫描了多少索引项,totalDocsExamined 扫描了多少文档,nReturned 返回多少文档。如果 totalDocsExamined 远大于 nReturned,说明扫描了大量无用文档;如果出现 COLLSCAN 或大范围 SORT,就要检查索引和查询条件。

追问:

  1. IXSCAN 和 COLLSCAN 区别是什么?
  2. totalDocsExamined 远大于 nReturned 说明什么?
  3. 排序慢怎么排查?

原理:MongoDB 基础:索引入门核心全过程原理

MongoDB 有索引为什么还可能慢

text
MongoDB 走索引不代表一定快。要看 totalKeysExamined、totalDocsExamined 和 nReturned 的比例。如果扫描大量索引项和文档只返回少量结果,说明索引选择性差或复合索引顺序不匹配;如果计划里有 SORT,说明排序没有被索引满足;如果需要 FETCH 大量原始文档,也会慢。目标不是只看到 IXSCAN,而是让扫描量接近返回量,并避免大范围排序。

追问:

  1. IXSCAN 后为什么还会有 FETCH
  2. 什么是覆盖查询?
  3. totalKeysExamined 很大说明什么?

原理:索引设计:查询有索引为什么还可能慢索引设计:覆盖查询

MongoDB 复合索引字段顺序怎么定

text
复合索引字段顺序要根据查询模式设计,常见思路是等值过滤字段在前,再考虑排序字段和范围字段。例如按 hospitalId、status 过滤并按 createdAt 倒序查询,可以建立 { hospitalId: 1, status: 1, createdAt: -1 }。设计后必须用 explain 验证扫描索引项和扫描文档数是否接近返回数量。

追问:

  1. 为什么不能看到字段就建索引?
  2. ESR 原则是什么?
  3. 索引越多为什么写入越慢?

原理:MongoDB 高级:ESR原则索引设计

MongoDB ESR 原则是什么

text
ESR 是复合索引设计的常用思路,E 表示 Equality 等值条件,S 表示 Sort 排序字段,R 表示 Range 范围条件。比如按 hospitalId、status 等值过滤,并按 createdAt 倒序分页,可以建立 { hospitalId: 1, status: 1, createdAt: -1 }。这样先定位医院和状态,再按时间顺序取数据。ESR 不是死规则,还要结合字段区分度、查询频率和 explain 验证。

追问:

  1. 为什么 createdAt 放最前面可能不好?
  2. 排序字段和范围字段同时存在怎么设计?
  3. ESR 为什么还要 explain 验证?

原理:索引设计:ESR原则讲清楚

MongoDB skip 深分页为什么慢

text
skip 深分页慢,是因为数据库不是直接跳到第 N 条,而是要按索引或排序顺序扫描并丢弃前 N 条,再返回 limit 条。skip 越大,浪费越多。列表无限滚动更推荐游标分页,例如按 createdAt 和 _id 作为稳定锚点继续查询下一页。

追问:

  1. 为什么只用 createdAt 做游标可能重复或漏数据?
  2. 游标分页能不能任意跳页?
  3. 深分页和排序索引有什么关系?

原理:索引设计:skip深分页为什么慢

MongoDB TTL 索引适合什么

text
TTL 索引用于让文档按时间自动过期,适合验证码、临时 token、短期日志等临时数据。TTL 删除不是精确实时删除,也不适合核心业务数据。订单、资产、审计这类重要数据不能直接靠 TTL 删除,应先归档或走业务清理流程。

追问:

  1. TTL 删除是否精确到秒?
  2. TTL 为什么不适合核心业务数据?
  3. 日志保留策略怎么设计?

原理:MongoDB 高级:TTL索引

MongoDB 聚合管道为什么要先 match

text
聚合管道是一段一段处理文档流。越靠前的阶段处理的数据越多,所以要尽早 $match 过滤,尽早 $project 裁剪字段,再做 $group、$sort、$lookup 这类重操作。如果先 group 或 sort 全量数据,再过滤,就会放大 CPU、内存和磁盘压力。高频报表不应该每次实时扫全量,应该考虑预聚合、异步导出或数仓。

追问:

  1. $project 为什么能优化聚合?
  2. $group$sort 为什么重?
  3. 什么场景应该预聚合?

原理:聚合管道:聚合管道怎么执行聚合管道:医疗资产按科室统计

MongoDB $lookup 有什么风险

text
$lookup 可以做集合关联,但不能把 MongoDB 当关系库无限 Join。高频复杂 lookup 通常说明文档模型或冗余设计需要重新评估。lookup 前要先 match 缩小主集合,foreignField 要有索引,并控制返回字段。如果只是资产列表展示科室名称,且科室名称变化很少,可以考虑冗余 departmentName,避免每次实时关联。

追问:

  1. $lookup 的 foreignField 为什么要建索引?
  2. 冗余字段有什么代价?
  3. 什么场景更适合数仓或预聚合?

原理:聚合管道:lookup为什么要谨慎

MongoDB allowDiskUse 是不是性能优化

text
allowDiskUse 允许聚合中的部分大排序、大分组把临时数据写到磁盘,能避免内存限制错误,但不是性能优化本身。磁盘临时文件通常比内存慢,也会影响整库 IO。如果接口长期依赖 allowDiskUse 才能跑完,应该考虑缩小过滤范围、补索引、预聚合、异步导出或进入数仓。

追问:

  1. allowDiskUse 解决什么,不解决什么?
  2. 大聚合为什么可能打磁盘?
  3. 为什么高频报表不适合每次实时聚合?

原理:聚合管道:allowDiskUse是不是万能解

MongoDB oplog 是什么

text
oplog 是复制集用于同步的操作日志。Primary 写入后把操作记录到 oplog,Secondary 拉取并重放这些操作保持数据同步。oplog 是有大小限制的循环日志,如果 Secondary 落后太久,所需 oplog 已被覆盖,就需要重新同步。复制延迟会影响读从库的数据新鲜度。

追问:

  1. oplog 和普通业务日志有什么区别?
  2. Secondary 为什么会落后?
  3. oplog 窗口太短有什么风险?

原理:MongoDB 高级:复制集核心全过程原理

writeConcern 怎么理解

text
writeConcern 控制写入需要达到什么确认级别。w:1 表示 Primary 写入成功即可返回,性能较好但风险更高;w:"majority" 表示多数节点确认后返回,可靠性更强;配合 j:true 可以要求写 journal。核心数据不能只看低延迟,要根据数据重要性选择合适 writeConcern。

追问:

  1. w:1 和 majority 的区别是什么?
  2. writeConcern 和复制延迟有什么关系?
  3. 什么业务应该用更强写关注?

原理:MongoDB 高级:选举和写关注

readPreference 有什么风险

text
readPreference 控制读请求从 Primary 还是 Secondary 读取。读 Secondary 可以分担读压力,但可能读到旧数据,因为复制存在延迟。用户刚写完马上读、订单支付状态、资产状态变更这类强实时场景通常应读 Primary 或设计读写一致策略,不能无脑读从库。

追问:

  1. secondary 读为什么可能读到旧数据?
  2. 什么场景可以读从库?
  3. 读写分离为什么会有一致性问题?

原理:MongoDB 高级:读偏好

shard key 怎么选

text
shard key 决定数据如何分布到不同 shard。好的 shard key 要让写入均匀、查询能带上 shard key、数据不倾斜、不产生热点。自增时间字段容易让新写入集中到一个分片;低基数字段如 status 会严重倾斜;随机字段写入均匀但范围查询差。分片前应先确认单机真的无法承载,并准备好备份、监控和运维能力。

追问:

  1. 为什么时间递增字段可能形成写热点?
  2. 为什么低基数字段不适合做 shard key?
  3. 分片为什么不是性能问题第一解?

原理:MongoDB 高级:分片shard key选择

副本集能不能替代备份

text
不能。副本集解决节点故障和高可用,Primary 上的误删、误更新也会通过 oplog 同步到 Secondary。备份解决误删、灾难恢复和历史时间点恢复。生产环境需要副本集、备份、恢复演练和监控一起设计,不能认为有多个副本就不需要备份。

追问:

  1. 误删数据为什么会同步到副本?
  2. 副本集和备份分别解决什么?
  3. 备份为什么必须做恢复演练?

原理:MongoDB 高级:备份和监控