MongoDB速记

MongoDB 核心考点速记笔记(锚定实习 RBAC 版本模型代码)

定位:写在 za-lincoln 技术栈里必被问。目标------概念题秒答,且每题都能落到"我实习怎么用的"。


一、MongoDB 是什么 & 与 MySQL/Redis 选型(必考第一问)

  • 定位: 面向文档的分布式数据库(BSON 文档 = 二进制 JSON),Schema 灵活(同集合文档结构可不同),原生支持水平扩展(分片)与副本集高可用。

  • 三选型一句话:

    • MySQL: 关系强、多表 JOIN、事务强一致(钱、账)→ 结构化核心数据。
    • MongoDB: 写多读少或结构多变、嵌套层次深、聚合统计(日志、配置版本、画像、内容)→ 免 JOIN 的对象型数据。
    • Redis: 纯缓存/高频读写,数据可丢或可重建。
  • 实习锚点: RBAC 权限版本(roles 是嵌套 Map:角色→资源→操作三层嵌套)------关系库要拆 5 张表 + 5 次 JOIN,MongoDB 一个文档一次读出,这就是选它的理由(面试原话)。


二、文档模型核心概念(对齐 MySQL 词汇表)

MySQL MongoDB
Database Database
Table Collection
Row Document(BSON)
Column Field
主键 _id(默认 ObjectId:12 字节 = 4 时间戳 + 5 机器随机 + 3 计数器)
JOIN 嵌入式文档 (或 $lookup,性能差少用)
  • 嵌套 vs 引用(经典设计题): "一起读、强从属" → 嵌入( RBAC 的 roles);"独立生命周期/多对多" → 引用(分集合 + 应用层组装)。
  • 反范式陷阱: 嵌入文档无限膨胀(16MB 上限)→ 大数组要拆出集合。

三、必备查询与更新语法(写过的才敢说熟)

  • 查询: db.col.find({age: {$gt: 18}}, {name: 1});$in/$ne/$exists;数组匹配是"包含"语义 ({tags: "a"} 匹配数组含 a 的文档)。

  • 投影: 第二个参数选字段(_id 默认带,_id: 0 关掉)。

  • 更新三兄弟(辨析必考):

    • updateOne/Many + $set (只改指定字段;不写 $set 会整文档替换------新手大坑)。
    • $setOnInsert: 只在 upsert 插入新文档时生效,已有文档不动------RBAC 草稿创建用它保护已存在草稿的字段不被覆盖。
    • $inc: 原子自增(计数器场景)。
  • upsert: 查到则更新、没查到则插入(upsert: true)------必须配唯一索引 防并发双插(与 MySQL ON DUPLICATE KEY UPDATE 同思想,见项目篇-1)。

  • findAndModify(实习核心武器): "查找+修改+返回修改后文档"一条原子命令 。RBAC 的 getOrCreateDraftRole 用 findAndModify + upsert + returnNew 实现"存在草稿就返回、没有就创建"------不加锁天然幂等 ,等价于"带返回值的原子 upsert"(比 update + 再查一次 的两步竞态安全)。


四、索引与执行计划

  • 索引类型: 单字段、复合索引 (同样遵循最左前缀)、唯一索引 (防重)、TTL 索引(到期自动删文档,日志/会话场景)、文本/Atlas 全文索引(一般交给 ES,别硬扛)。
  • 索引底层: B+ 树(和 MySQL 一样,3.0+ WiredTiger 引擎;早期 MMAPv1 是 B 树------说"Mongodb 是 B 树"是老黄历)。
  • explain: db.col.find(...).explain("executionStats"),看 totalDocsExamined vs nReturned(扫描/返回比 = 索引效率)。
  • 慢查询三板斧: profiler(db.setProfilingLevel(1, {slowms: 100}))→ explain 看是否全扫 → 补索引/改查询。

五、事务与一致性(高频追问)

  • 单文档原子性: 单文档的更新(含嵌套数组操作、findAndModify)天然原子------多数场景根本不需要多文档事务(这是 MongoDB 的设计哲学,先说这句加分)。
  • 多文档事务: 4.0 起副本集支持、4.2 起分片支持,用法 session.startTransaction()。代价: 性能差(跨节点协调)、默认 60s 超时------能用单文档原子 + 应用层补偿就不用多文档事务。
  • 实习锚点: RBAC 版本激活"先置新 VALID 再废旧 VALID"两步用 BulkWrite 一次提交 ,且顺序故意反着来 :先废后立会出现"无 VALID 版本"窗口(查询报错),先立后废只是"暂时双 VALID"(查询仍能返回)------用顺序设计规避分布式事务,面试讲出来就是设计功底。
  • 写关注(Write Concern): w:1(主节点确认,默认)/ w:majority(过半确认,防主从切换丢写)/ w:0(不等确认,最快)。要求不丢写 → majority + journal。

六、副本集与分片(架构层必考)

1. 副本集(Replica Set)------ 高可用

  • 角色: 1 Primary(唯一写入口)+ N Secondary(同步复制 oplog)。
  • 选举: Sentinel 式?不------基于 Raft 思想 的自身协议,多数派投票选出新主(默认约 10s 心跳超时,任期 term 防脑裂)。类比记忆:MySQL 主从 + Raft 选举的合体。
  • Secondary 三种形态: 普通备份 / Priority 0 (永不参选)/ Hidden(对客户端不可见,专给报表)。
  • 读写分离: readPreference=secondaryPreferred 读从库------接受最终一致,写永远走主。
  • oplog: 主库的操作日志(幂等可重放的幂等性 op),从库拉取回放------类比 MySQL binlog(但 oplog 是幂等格式,重放安全)。

2. 分片(Sharding)------ 水平扩展

  • 三大组件: mongos(路由,无状态)+ Config Server(元数据,副本集)+ Shard(数据片,各自是副本集)。
  • 分片键(Shard Key): 决定文档落哪个片。必须建在分片键上的查询才只路由到单片(否则广播全片)。
  • 两类策略: 范围分片 (range,易理解但易热点------单调递增键全打到最后一片)vs 哈希分片(hash,均匀但牺牲范围查询)。默认哈希更常用。
  • vs 手动分库分表(MySQL): Mongo 分片是数据库原生自动的(应用无感知、自动均衡 rebalance),MySQL 要中间件/应用层搞------这就是"结构多变 + 需要水平扩展"场景选 Mongo 的第二个理由。
  • jumbo chunk / 热点: 单个分片键值过大无法分裂 → 选高基数(取值多)的分片键。

七、存储引擎与内存(WiredTiger)

  • WiredTiger(3.2+ 默认): 文档级并发控制(读写锁粒度到文档,高并发写入强)+ 快照隔离 MVCC + B+ 树索引。
  • 缓存: 默认约 (RAM - 1GB) / 2 为 WiredTiger Cache------MongoDB 吃内存是设计使然(热数据全在 cache 才快),生产独占机器、别和 MySQL 挤一台。
  • 日志: journal(WAL 预写日志,崩溃恢复,类比 InnoDB redo log)+ checkpoint。

八、Aggregation 聚合管道(替代复杂 SQL 的武器)

  • 管道思想: $match → $group → $sort → $limit 一条管道流式处理,等价于 SQL 的 WHERE/GROUP BY/ORDER BY。
  • 高频算子: $match(尽量放最前面,先过滤少过数据)、$group + $sum/$avg、$project(投影)、$unwind(数组炸开成多行)、$lookup(左连接,能不用就不用)。
  • 实战锚点: RBAC 的"角色数量、权限覆盖度统计"(findAllApiResources 后算覆盖)就是聚合管道------和 SQL 对着讲("把 GROUP BY 换成 $group 而已")。

九、实习项目深挖预案(背熟这三问三答)

  1. "为什么 RBAC 用 MongoDB 不用 MySQL?"

    "三层嵌套结构(角色→资源→操作)在关系库要拆 5 张表 + 5 次 JOIN,读一个完整版本要拼装;Mongo 一个文档整存整取,且版本快照这种'写少读多、按版本整体读取'的模式和文档模型天然匹配。事务弱点的风险我们用单文档原子操作 + 顺序设计(先立后废)规避了。"

  2. "并发发布两个草稿怎么办?"

    "Redis 分布式锁 + 锁内双重校验 + Mongo 版本号自增;草稿获取本身用 findAndModify+upsert 原子幂等,连锁都不用。"

  3. "MongoDB 事务了解吗?"

    "单文档天然原子;多文档 4.0+ 支持但我们没用------BulkWrite 一次提交两步更新 + 反序设计替代了它,性能更好。"


十、自测清单

  • 文档 vs 关系选型的三个判据?ObjectId 的组成?
  • findAndModify + upsert 为什么是原子的?$setOnInsert 干嘛的?
  • 先废后立 vs 先立后废的窗口差异?BulkWrite 是原子的吗?
  • 副本集选举基于什么思想?oplog 类比 MySQL 什么?为什么是幂等的?
  • 分片键两类策略的取舍?什么查询会广播?
  • WiredTiger 的并发控制粒度?为什么 Mongo 吃内存是正常的?
相关推荐
system_error_x11 分钟前
SpringBoot 集成 Thymeleaf 简洁入门
java·spring boot·后端
步行cgn2 小时前
Spring MVC 视图机制的核心接口与类
java·开发语言·后端·spring·mvc
码事漫谈3 小时前
AI 读你的提示词,其实很没耐心
后端
用户8356290780513 小时前
如何使用 Python 格式化 Excel 单元格中的长文本
后端·python
我命由我123453 小时前
Python 开发 - Python 的 pathlib
java·开发语言·后端·python·学习·java-ee·学习方法
IT_陈寒3 小时前
Java性能优化完全指南
前端·人工智能·后端
电子IT笔记3 小时前
对接群晖NAS,上传和删除踩坑记录
前端·后端
Mk598784 小时前
P4:把 Agent 的记忆搬进 Redis —— AgentScope-Java 工程化实战
后端
雨中飘荡的记忆4 小时前
Claude Code 入门必会:@、!、Slash Commands,一篇讲清楚
人工智能·后端
用户8356290780514 小时前
如何使用 Python 在 Word 文档中创建和格式化列表
后端·python