36.MongoDB总结

  1. 36.MongoDB总结
    1. 36.1 核心要点速览
      1. SQL 和 NoSQL
      2. NoSQL 类型对比
      3. MongoDB下载安装
        1. 步骤
        2. 安装选项对比表
      4. MongoDB配置文件
      5. MongoDB相关工具
      6. MongoDB连接和启用认证
      7. MongoDB的ObjectID
      8. MongoDB插入
      9. MongoDB查询
        1. MongoDB基础查询
        2. MongoDB数组查询和嵌套字段查询
        3. MongoDB多条件查询
        4. MongoDB指定字段查询
        5. MongoDB模糊查询
        6. MongoDB排序查询
        7. MongoDB分页查询
        8. MongoDB聚合查询概念
        9. MongoDB过滤文档聚合查询
        10. MongoDB分组聚合查询
        11. MongoDB排序聚合查询
        12. MongoDB分页聚合查询
      10. MongoDB索引
        1. 索引概念
        2. 单字段索引
        3. 复合索引
        4. 文本索引
        5. 哈希索引
        6. 地理空间索引
        7. 稀疏索引
        8. 唯一索引
        9. 部分索引
        10. 操作对比
      11. MongoDB更新
        1. 首条更新 (updateOne)
        2. 多条更新 (updateMany)
        3. 替换更新 (replaceOne)
        4. 操作对比
      12. MongoDB删除
        1. deleteOne
        2. deleteMany
        3. findOneAndDelete
        4. drop
        5. remove (弃用)
        6. 操作对比
      13. MongoDB联动C#
        1. C#操作MongoDB
        2. C#使用Bson操作MongoDB
    2. 36.2 面试题精选
      1. 基础题
        1. 1. 关系库和文档库/键值库:「最小存储单元」分别长什么样?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        2. 2. ACID 四个字母各指什么?转账场景里分别挡的是哪类事故?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        3. 3. ObjectId 的 12 字节怎么切?为什么说 _id 排序只有「大致」时间序?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        4. 4. 复合索引 { a: 1, b: 1 }:什么叫最左前缀?哪种查询「以为能走其实常走不上」?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
      2. 进阶题
        1. 1. 垂直扩展与水平扩展各是什么?和 SQL / NoSQL 的常见画像怎么对应?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        2. 2. 键值、列式、文档三类:各举一个「最划算」的负载,再各举一个「明显别选」的反例。
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        3. 3. 聚合管道 aggregate([...]) 在模型上是什么?$match 为什么要尽量靠前?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        4. 4. 深分页里 skip 为什么贵?用 _id 做游标分页时 filter 怎么写?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
      3. 深度题
        1. 1. 别背 CAP:用「读到的后果」区分强一致与最终一致,各举一例。
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        2. 2. 关系型范式化 vs 文档嵌套与冗余:从读、写、改模式各说一个权衡。
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        3. 3. 开发机一直用 bindIp: 127.0.0.1,上线要对外开放:风险链怎么讲?最小加固清单列哪几项?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章
        4. 4. 稀疏索引与部分索引各解决什么数据形态?为何不能在同一条索引上同时写 sparse 与 partialFilterExpression?
          1. 题目
          2. 深入解析
          3. 答题示例
          4. 参考文章

36.MongoDB总结


36.1 核心要点速览

SQL 和 NoSQL

  • 选型时除了「有没有表结构」,还要看数据结构化程度、一致性要求、查询形态、扩展方式、典型业务是否匹配;下面总表与开篇对比维度(数据结构、一致性、查询、扩展、典型场景)对齐,可一起记。
  • 扩展:SQL 常见路径是垂直扩展(更强单机);NoSQL 体系更常按水平扩展(加节点分片)来设计容量。
  • 一致性叙事:账务、支付等多用强一致 + 事务说话;时间线、统计类场景往往接受最终一致,换吞吐与可用性。
对比维度 SQL NoSQL
数据模型 - 表格(行×列)
- 固定模式(Schema)
- 文档(JSON/BSON)、键值、列族、图
- 动态模式,灵活
查询语言 - 标准化 SQL
- 支持复杂查询、聚合、联表
- 各自接口(如 MongoDB 查询、Redis GET)
- 依赖具体实现
事务支持 - 完整 ACID(原子性、一致性、隔离性、持久性) - 通常“最终一致”
- 部分产品支持限域事务
性能 - 优化后复杂联表与事务性能优
- 适合结构化查询
- 高并发、低延迟
- 大规模水平扩展
适用场景 - 金融、电商等高一致性需求
- 复杂关系建模
- 日志、社交、物联网等半/非结构化数据
- 高吞吐缓存
优势 - 生态成熟、工具丰富
- 数据完整性高
- 扩展性强、灵活性高
- 支持多样数据模型
局限 - 模式固定、扩展复杂
- 海量并发场景受限
- 标准化查询缺失
- 复杂事务与关联查询能力弱

NoSQL 类型对比

  • 本篇对比键值、列式、文档三类:键值极简单、延迟低;列式偏读少列、分析型;文档型在半结构化业务数据灵活查询之间折中,MongoDB 属于这一类。
  • 没有「万能 NoSQL」:先问数据是不是键值就够、是不是分析扫列、是不是文档嵌套更合适,再选代表产品。
类型 代表工具 主要优点 主要缺点
键值存储 Redis、Memcached、DynamoDB - 超高性能
- 简单模型
- 易水平扩展
- 仅键值对
- 无复杂查询
- 一致性风险
列式存储 HBase、Cassandra、Bigtable - 列级压缩高效
- OLAP 分析优
- 写入与更新慢
- 全表/多列查询低效
文档存储 MongoDB、CouchDB、Couchbase - 结构灵活
- 水平扩展
- 强查询功能
- 事务与一致性弱
- 复杂建模难

MongoDB下载安装

步骤

  • 获取安装包

    • 官方下载页获取 Community Edition
    • 可选格式:msi(向导式安装)、zip(便携解压)、Docker 镜像
  • 安装流程

    • 对于 msi:一路“Next”完成
    • 对于 zip:解压后手动配置环境变量
    • 对于 Docker:拉取镜像并运行容器
  • 服务运行账户

    • Network Service user:Windows 内置低权限账户,安全风险最小
    • Local User / Domain User:自定义账户,可精细控制文件与网络访问
    • 仅影响操作系统层面权限,不改动数据库内部用户认证
  • 可选组件

    • MongoDB Compass:官方 GUI 可视化管理工具,命令行不熟悉者推荐
    • 可根据需求勾选,无需强制安装
  • 安装后验证

    • 打开“服务”窗口,确认 “MongoDB” 服务存在且设为“自动”启动
  • 形态选择

    • msi 适合本机快速装服务;zip 适合自定义目录与脚本化;Docker 适合隔离环境与版本对齐,三者数据目录与配置仍要落在安全、可备份的磁盘上。

安装选项对比表

安装环节 可选项 适用场景与说明
安装包类型 msi
zip
Docker
向导安装 / 便携版 / 容器化部署
服务账户 Network Service user
Local/Domain User
内置低权限 / 自定义权限,适合不同安全与企业环境需求
GUI 管理工具 MongoDB Compass 图形界面管理,适合不熟悉命令行的用户
安装验证 Windows 服务管理 确认 “MongoDB” 服务已安装、启动类型为“自动”

MongoDB配置文件

  • 配置文件类型

    • mongod.cfg(Windows 安装向导生成)
    • mongod.conf(Linux/macOS 原生,Windows 亦可)
  • 文件格式对比

    • Key-Value:安装程序生成,格式简单
    • YAML:官方推荐,结构清晰,便于维护
  • 常用配置项

    • systemLog:日志路径与方式
    • storage:数据目录与存储引擎
    • net:绑定 IP 与端口
    • security:开启授权认证
    • processManagement:守护进程与 PID 文件
  • 生效方式

    • 配置文件:mongod --config /path/to/mongod.conf
    • 命令行:--dbpath, --logpath, --bind_ip, --port, --auth
  • 网络与安全

    • 示例里常见 bindIp: 127.0.0.1,表示仅本机可连;若要远程访问,须同时改绑定地址、系统防火墙、并启用认证(否则等于把库暴露在公网)。
配置文件 默认平台 格式 适用场景
mongod.cfg Windows Key-Value 安装向导生成的简易配置
mongod.conf Linux/macOS(*) YAML 官方推荐,易于扩展维护
配置项 作用 常见字段示例
systemLog 日志输出位置与模式 destination, path
storage 数据目录与存储引擎选项 dbPath
net 网络绑定地址与监听端口 bindIp, port
security 用户认证与授权 authorization: enabled
processManagement 守护进程模式与 PID 文件 fork, pidFilePath

MongoDB相关工具

  • 官方工具

    • mongosh:命令行交互,脚本与自动化管理
    • Compass:GUI 可视化,拖拽式查询与分析
  • 第三方工具示例

    • Robo 3T / Studio 3T:增强型界面与导出功能
    • DbGate:跨 DB 多引擎统一管理
  • CLI 使用流程

    • 下载并解压或安装
    • 启动工具后输入连接字符串
    • 常用命令:show dbsuse <db>show collectionsdb.collection.insertOne()
工具名称 类型 主要用途
mongosh CLI 脚本化管理,自动化操作
Compass GUI 可视化数据浏览、查询与性能分析
Robo 3T GUI 轻量级图形界面,支持多种导出与插件
DbGate GUI/多引擎 多数据库统一管理,支持自定义查询与插件安装

MongoDB连接和启用认证

  • 连接字符串格式

    • mongodb://<user>:<pwd>@<host>:<port>/<db>?options
    • 特殊字符需 URL 编码(@ → %40/ → %2F: → %3A? → %3F
  • 常用选项

    • authSource:在哪个库验票(管理员常在 admin)。
    • retryWrites:是否自动重试可重试类写入失败;默认值随驱动版本而变,连接串里写清楚最省心。
    • w / journal:写入确认级别,与副本集、一致性要求相关。
    • readPreference:副本集路由偏好(如 primarysecondary),和 w、读写分离一起设计。
    • sslconnectTimeoutMSsocketTimeoutMSmaxPoolSize 等:链路加密、超时与连接池上限。
  • 启用认证步骤

    • 在配置文件或启动参数中开启 authorization: enabled--auth
    • 用命令行连接到 admin 库,db.createUser(...) 创建管理员
    • 优雅停服:db.adminCommand({ shutdown: 1 }) 或系统服务命令
    • 重启带认证的服务,使用带凭证的连接字符串重新连接
步骤 方式 示例命令/字段
开启认证 配置文件 / 参数 security.authorization: enabled
--auth
创建管理员 mongosh use admin
db.createUser({...})
优雅关闭 mongosh / 系统服务 db.adminCommand({ shutdown: 1 })
net stop MongoDB
重启服务并连接 配置文件 / 参数 + URI mongod --config ...
mongodb://user:pwd@...

MongoDB的ObjectID

  • 定义与作用

    • 默认主键类型,12 字节 BSON,用于全局唯一标识文档
    • 十六进制字符串(24 字符)表现
  • 组成结构

    • 时间戳(4 字节):秒级 Unix 时间,保证排序性
    • 机器标识(3 字节):主机唯一哈希,区分节点
    • 进程 ID(2 字节):区分同机多进程生成
    • 随机计数器(3 字节):同时间内递增,防止冲突
  • 核心特性

    • 全局唯一性:组合信息确保不同环境无重复
    • 时间可提取:getTimestamp() 可还原创建时刻
    • 存储高效:仅 12 字节,比 UUID 更节省空间
  • 常见用法

    • 默认生成:插入文档时自动赋值
    • 查询筛选:find({ _id: ObjectId(...) })
    • 手动生成:var id = ObjectId()
    • 获取创建时间:ObjectId("…").getTimestamp()
    • 转十六进制字符串:现行 mongosh 常用 ObjectId("…").toString()(与 shell 版本一致即可)
组成部分 字节数 主要用途
时间戳 4 保证生成顺序与时间关联
机器标识 3 区分不同主机
进程 ID 2 区分同机不同进程
随机计数器 3 同秒内生成唯一性

MongoDB插入

  • insertOne(单条插入)

    • 语法:db.collection.insertOne(document, options)
    • 自动生成 _id(若未指定),或使用自定义 _id
    • 可选 writeConcernbypassDocumentValidation
    • 返回 { acknowledged: true, insertedId: <_id> }
  • insertMany(批量插入)

    • 语法:db.collection.insertMany([doc1, doc2, …], options)
    • 一次插入多条文档
    • 返回 { acknowledged: true, insertedIds: […] }
  • 冲突处理

    • 若指定的 _id 已存在,抛出 MongoServerError: E11000 duplicate key error
    • 可在应用层捕获并处理,或改用 upsert 等方式
  • insertOne vs. insertMany 对比

操作 场景 参数 返回值 注意事项
insertOne 单文档写入 document, options { acknowledged, insertedId } _id 自动/手动,冲突报错
insertMany 批量写入 Array<document>, options { acknowledged, insertedIds } _id 冲突报 E11000;批量是否「一条失败就停」由 insertMany 的选项控制,以当前版本文档为准

MongoDB查询

  • 入口find(filter, projection)filter{} 时可匹配全部文档,生产仍应带条件并配合索引。
  • 投影:除 _id 外,同一 projection 不能混用「只返回若干字段的 1」与「排除若干字段的 0」;_id: 0 可与 inclusion 搭配。
  • 正则$regex 易触发全表扫描,热点检索要考虑索引或换搜索方案。
  • 排序与分页:字符串按 Unicode,数字存成字符串时 "10" 会排在 "2" 前;深分页避免超大 skip,大集合优先用基于 _id 或稳定排序键的游标翻页。

MongoDB基础查询

  • 方法db.collection.find(query, projection)

  • 常见操作

    • 等于 $eq、不等 $ne、大于 $gt、小于 $lt、…
    • 字段存在 $exists、类型匹配 $type
  • 示例

    db.users.find({ age: { $gte: 25 } }, { name: 1 })
    
操作 语法 说明
等于 { age: 25 } age 精确匹配 25
范围查询 { age: { $gt:25, $lt:30 } } age 在 (25,30) 之间
字段存在 { score: { $exists:true } } 仅返回含有 score 字段的
类型匹配 { age: { $type:"int" } } age 必须为整数

MongoDB数组查询和嵌套字段查询

  • 数组查询

    • $in / $nin:数组中是否出现列表里任一值;$nin无该字段的文档也会匹配,语义上要心里有数。
    • 标量数组上「某个元素满足比较」:直接写 { arr: { $gt: 2 } } 等,服务器按元素比对。
    • $elemMatch:用于元素为子文档的数组,且要求同一个元素同时满足多条条件(子文档内 AND)。
  • 嵌套字段

    • 点语法 "bag.index": value 或范围 { "bag.index": { $gt: 0 } }
db.users.find({ lessons:{ $in:[1,4] } })
db.users.find({ lessons:{ $gt:2 } })
db.users.find({ "bag.index":1 })
功能 操作符 / 写法 作用
包含任一元素 { lessons:{ $in:[…] }} 数组出现过列表中任一项
排除列表 { lessons:{ $nin:[…] }} 无字段或数组不含列表中任一项(注意缺字段语义)
标量元素比较 { lessons:{ $gt:2 } } 至少一个元素满足该比较
文档元素多条件 { arr:{ $elemMatch:{ a:1,b:2 } } } 存在一条子文档同时满足子条件
嵌套字段精确 { "bag.index":1 } 子文档字段精确匹配

MongoDB多条件查询

  • AND(隐式):多个字段同级条件
  • OR{ $or:[cond1,cond2] }
  • 复合:AND + $or
db.users.find({ age:25, $or:[{name:"T1"},{name:"T2"}] })
查询类型 语法 示例
AND { a:1, b:2 } 同时满足 a=1 且 b=2
OR { $or:[{a:1},{b:2}] } a=1 或 b=2
组合查询 { c:3, $or:[…] } c=3 且 (a=1 或 b=2)

MongoDB指定字段查询

  • Projection:第二参数 { field:1 } 包含,{ field:0 } 排除
  • **默认返回 _id**,可显式 { _id:0 }
  • 支持嵌套字段{ "bag.index":1 }
db.users.find({}, { name:1, age:1, _id:0 })
方式 语法 说明
包含字段 { name:1, age:1 } 仅返回 name 和 age
排除字段 { age:0 } 返回所有字段但不包括 age
排除 _id { _id:0 } 不返回 _id

MongoDB模糊查询

  • **正则 $regex**:字符串模式匹配
  • 忽略大小写$options:"i"
  • 常用模式^$.*[]|
db.users.find({ name:{ $regex:"^T", $options:"i" } })
场景 语法 说明
包含子串 { name:{ $regex:"Ta" }} 匹配包含 “Ta”
开头匹配 { name:{ $regex:"^T" }} 以 T 开头
结尾匹配 { name:{ $regex:"2$" }} 以 2 结尾
忽略大小写 { name:{ $regex:"t", $options:"i" }} 不区分大小写

MongoDB排序查询

  • .sort({ field:1|-1 }):1 升序,-1 降序
  • 支持多字段:按字段顺序依次排序
db.users.find().sort({ age:1, name:-1 })
排序方式 语法 说明
单字段升序 { age:1 } age 从小到大
单字段降序 { age:-1 } age 从大到小
多字段排序 { age:1, name:-1 } age 再 name

MongoDB分页查询

  • skip(n).limit(m):跳过 n,取 m 条
  • 游标分页{ _id:{ $gt:lastId }} + limit
  • 排序分页:结合 .sort() + skip/limit
db.users.find().skip(10).limit(5)
db.users.find({ _id:{ $gt:objId } }).limit(5)
方法 优缺点 用例
skip/limit 简单;大量 skip 性能差 小数据量分页
游标分页 高效;依赖递增键;不支持随机页 大数据集连续翻页
排序分页 指定顺序,结合 skip/limit 使用 需按特定字段分页

MongoDB聚合查询概念

  • Aggregation Pipelineaggregate([ 阶段1, 阶段2, … ]),上一阶段输出即下一阶段输入。
  • 每阶段输入→处理→输出,可组合成统计、清洗、联表式多步变换。
  • 典型阶段$match$group$sort$skip$limit$project 等。
  • 习惯:尽量把 $match 靠前,先减掉文档量,再分组排序,省 CPU 与内存。

MongoDB过滤文档聚合查询

  • $match:在管道中做过滤,查询算子与 find 同一套,可接 $group$project 等。
  • find 的差别:在管道里只是一阶段,后面还能继续变形;尽量靠前以缩小后续工作集。
db.collection.aggregate([ { $match:{ age:{ $gt:25 } } } ])
操作符 用途 示例
$match 文档过滤 { $match:{ status:"A" } }

MongoDB分组聚合查询

  • $group:类似 SQL GROUP BY
  • _id 定义分组键;写 _id: null 时表示全表聚成一组(全员汇总)。
  • 常用累加器$sum$avg$max$min$first$last$push$addToSet
  • $first / $last:取组内第一条或最后一条的字段值,依赖进入 $group 时的文档顺序,要「谁算第一」通常先 $sort
db.sales.aggregate([
  { $group:{ _id:"$item", total:{ $sum:"$quantity" } } }
])
累加器 功能 示例
$sum 求和 { totalQty:{ $sum:"$qty" } }
$avg 平均值 { avgPrice:{ $avg:"$price" } }
$max/$min 组内最值 { hi:{ $max:"$score" } }
$push 收集为数组 { allQty:{ $push:"$qty" } }
$addToSet 收集去重集合 { ids:{ $addToSet:"$userId" } }
$first / $last 组内首条/末条字段 常配合前置 $sort 才有业务含义

MongoDB排序聚合查询

  • $sort:管道内排序,多键顺序find().sort() 相同(先第一键,再第二键)。
  • 性能:大数据量、无索引支撑时排序昂贵;管道默认有单阶段内存上限(常见为 100MB 量级),超标可报错。
  • allowDiskUse: true:允许排序等阶段溢出到磁盘,避免一味加大内存(见正文 aggregate(..., { allowDiskUse: true }))。
db.students.aggregate([ { $sort:{ score:-1, age:1 } } ])
排序符号 含义
1 升序
-1 降序

MongoDB分页聚合查询

  • $skip + $limit:管道内分页;skipfind 一样贵,深分页仍优先考虑排序键游标或改产品形态。
  • 顺序:要稳定顺序时 **$sort$skip$limit**;可与 $project 组合先裁字段再取页(见正文)。
db.students.aggregate([
  { $sort:{ age:1 } },
  { $skip:5 },
  { $limit:5 }
])
阶段 描述
$skip 跳过指定文档数
$limit 限制返回文档数

MongoDB索引

  • 读写权衡:索引加速过滤与排序,但每次写入要维护所有相关索引,索引越多写路径越重
  • 按访问模式建:先统计真实查询里的等值、范围、排序、唯一性,再决定单字段、复合或专用索引,避免盲建闲置索引。
  • 部分与稀疏:同一条索引上 sparsepartialFilterExpression 不能同时指定;部分索引还要求查询条件能蕴含 partialFilterExpression,否则规划器可能不用(见第 29 篇)。

索引概念

  • 常见单字段/复合索引底层为 B-tree,便于等值与范围;无可用索引时多退化为集合扫描(COLLSCAN)
  • 相对全表逐个文档比对,命中高选择性索引时访问路径通常从 O(n) 量级降到对数级为主,仍与数据分布、选择性有关。
  • 每条索引占存储与缓存;插入/更新/删除会同步更新索引条目(正文对维护开销有展开)。

单字段索引

  • 针对单个字段创建升序(1)或降序(-1
  • 语法:db.coll.createIndex({ field: 1 });第二参数可设 name 自定义索引名
  • 列举索引:db.coll.getIndexes();删除:db.coll.dropIndex("索引名") 或传入 key 文档(与正文一致)
  • _id 默认唯一索引;覆盖查询时若过滤与投影字段均落在同一索引内,可减少回表读文档

复合索引

  • 多字段组合索引,字段顺序决定能否走索引:只查 b 不含 a 通常用不上 {a,b}
  • 语法:db.coll.createIndex({ a:1, b:-1 })排序方向若与查询 sort 一致,更易避免额外排序。
  • 前缀示例:索引 {a,b,c} 可服务 {a}{a,b}{a,b,c} 等左起连续条件(与第 23 篇一致)。

文本索引

  • 社区版典型路径:在查询条件里用 $text,内嵌 $search 指定关键词(如 { $text: { $search: "MongoDB" } },见第 24 篇);勿与 MongoDB Atlas Search 聚合管道里的 $search 阶段混为一谈。每个集合通常只允许一个 text 索引(多字段可合在同一 text 索引里)。
  • 语法:db.coll.createIndex({ title:"text", content:"text" })
  • 短语、排除词、textScore 排序、权重、多语言等见第 24 篇

哈希索引

  • 对字段值做哈希,仅利于等值查找
  • 语法:db.coll.createIndex({ key:"hashed" })
  • 不支持范围查询不能按哈希序做有序遍历,排序字段若只有哈希索引往往用不上(见第 25 篇)

地理空间索引

  • 2d:平面坐标(XY)索引;2dsphere:球面(经纬度)索引
  • 语法:db.coll.createIndex({ loc:"2dsphere" })
  • 支持 $near$geoWithin$centerSphere 等地理查询

稀疏索引

  • 仅索引包含该字段的文档,忽略字段缺失文档
  • 语法:db.coll.createIndex({ f:1 }, { sparse:true })
  • 节省空间,适合字段偶尔存在场景
  • 与唯一索引结合可对部分文档做唯一约束

唯一索引

  • 保证单字段或复合键组合唯一;集合内已存在重复值时建唯一索引会失败,需先清洗。
  • 语法:db.coll.createIndex({ email:1 }, { unique:true })

部分索引

  • partialFilterExpression 决定哪些文档进入索引;sparse 不可写在同一条索引
  • 语法:db.coll.createIndex({ f:1 }, { partialFilterExpression:{ status:"A" } })
  • 查询若与过滤式无关,可能不走该部分索引,需为其他访问路径另建索引。

操作对比

索引类型 创建语法 适用场景 支持特点 限制
单字段索引 { field:1 } 单字段查询、排序 覆盖索引 写入开销、所有文档均有索引条目
复合索引 { a:1, b:-1 } 多字段筛选与排序 前缀匹配 字段顺序敏感
文本索引 { f:"text", g:"text" } 全文搜索、短语、相关性排序 多字段、权重、多语言、停用词 字段类型限于字符串
哈希索引 { field:"hashed" } 精确值查询 等值查找高效 不支持范围/排序
地理空间索引 { loc:"2d" } / { loc:"2dsphere" } 位置搜索、地图应用 支持多种地理操作符 数据格式需 GeoJSON 或平面坐标
稀疏索引 { f:1 }, { sparse:true } 字段偶尔存在、减少无用索引条目 只索引存在字段的文档 不索引缺失字段文档
唯一索引 { f:1 }, { unique:true } 防止重复值 单字段或复合字段唯一性 创建前需清理重复数据
部分索引 { f:1 }, { partialFilterExpression: {...} } 特定条件优化 灵活过滤条件 仅对符合条件文档索引

MongoDB更新

  • 选型口诀:改几个字段用 updateOne / updateMany + 操作符;整份文档换成新形状用 replaceOne;条件写错时 updateOne 只动第一条,批量误伤用 updateMany 更危险。
  • arrayFilters:更新嵌套数组里满足子条件的元素时用占位符 $[标识],并在选项里写 arrayFilters(见第 31 篇)。

首条更新 (updateOne)

  • 针对匹配的第一条文档执行更新
  • 使用更新操作符:$set(设置/新增字段)、$inc(增减数值)、$unset(删除字段)等
  • 支持 upsert:true(无匹配时插入新文档;查询里带 $gt 等操作符的字段不会原样进新文档,见第 30 篇)
  • 常见选项:writeConcern(写入确认)、collation(排序规则)
  • 宽条件 + updateOne 易改错行,先 find 再改或加唯一键过滤

多条更新 (updateMany)

  • 针对所有匹配文档批量执行更新
  • 第二参数须为操作符文档或管道更新,语义同 shell 要求,不要replaceOne 的整文档替换混用
  • 支持 upsertarrayFiltershintcollationwriteConcern
  • 适用于:批量状态修改、计数器更新、数据清理

替换更新 (replaceOne)

  • 完整新文档替换匹配的第一条文档;新文档里没出现的字段会从原文档消失
  • 替换文档中的 _id 一般应与被替换文档一致;不能带 $set 等更新操作符
  • 选项支持 upsertcollationwriteConcern
  • 适用于:外部系统推来整包 DTO、需要文档形态与 schema 完全对齐时

操作对比

操作 更新范围 使用方式 文档保留 支持 Upsert 覆盖方式
updateOne 第一条匹配文档 使用更新操作符(如 $set, $inc 只改动指定字段 局部字段更新
updateMany 所有匹配文档 updateOne 只改动指定字段 局部字段更新
replaceOne 第一条匹配文档 提供完整替换文档(无更新操作符) 删除未包含字段 整个文档被新文档覆盖

MongoDB删除

deleteOne

  • 删除匹配的第一条文档
  • 语法:db.collection.deleteOne(filter, { collation })
  • 不返回被删文档
  • 只会删除第一个符合条件的,操作不可撤销

deleteMany

  • 删除所有匹配文档
  • 语法:db.collection.deleteMany(filter, { collation })
  • 不返回被删文档
  • {} 匹配全集,等同清空集合,执行前务必二次确认

findOneAndDelete

  • 查找并删除第一条匹配文档,同时返回它
  • 语法:db.collection.findOneAndDelete(filter, { sort, projection, collation })
  • 返回被删文档,便于后续处理
  • 可配合 sort 决定优先删除哪条

drop

  • 删除整个集合及其索引
  • 语法:db.collection.drop()
  • 一次性移除集合,无法恢复

remove (弃用)

  • 旧版删除方法,不推荐
  • 语法:db.collection.remove(filter, { justOne })
  • 功能已被 deleteOne/deleteMany 取代

操作对比

操作 删除范围 返回被删文档 典型场景
deleteOne 第一条匹配文档 删除某个条件下的单条记录
deleteMany 所有匹配文档 批量清理符合条件的数据
findOneAndDelete 第一条匹配文档 删除并需要获取被删文档(审计/日志)
drop 整个集合 清理整个集合及其索引
remove (弃用) 单条或多条(取决于 justOne 旧版代码兼容,建议迁移至新 API

MongoDB联动C#

C#操作MongoDB

驱动安装

  • 推荐通过 NuGet 安装 MongoDB.Driver,升级更便捷
  • 也可从 GitHub 获取源代码,适合自定义需求

连接与模型

  • MongoClient("mongodb://…") 全进程复用单例,线程安全;不要每次请求 new 一个
  • GetDatabaseGetCollection<T> 映射库与集合;强类型用 User 等 POCO + 特性,动态或异构结构用 GetCollection<BsonDocument>(见第 35 篇)
  • [BsonId][BsonRepresentation(BsonType.ObjectId)][BsonElement("name")] 等与 BSON 字段对齐

CRUD 操作

操作 API 说明
插入 InsertOne / InsertMany 同步插入单个或多个文档
查询 Find(filter).ToList() 支持 Lambda 表达式和 Builders
更新 UpdateOne(filter, update) $set$inc 等操作符,支持 upsert
替换 ReplaceOne(filter, replacement) 整文档替换
删除 DeleteOne / DeleteMany 精确条件删除单条或多条
索引 Indexes.CreateOne(new CreateIndexModel…) 为常用查询字段创建 B-Tree 索引

使用建议

  • 为高频查询字段建索引
  • 整个应用复用单个 MongoClient
  • 捕获 MongoException 并记录,保证健壮性

C#使用Bson操作MongoDB

BSON 文档构建与插入

  • var doc = new BsonDocument { … } 支持嵌套 BsonDocumentBsonArray
  • collection.InsertOne(doc)

BSON 查询与筛选

var all = collection.Find(new BsonDocument()).ToList();
var filtered = collection.Find(new BsonDocument("age", new BsonDocument("$gt", 25))).ToList();

BSON 更新与删除

操作 调用示例
更新 collection.UpdateOne( new BsonDocument("name","John"), new BsonDocument("$set", new BsonDocument("age",35)) )
删除 collection.DeleteOne( new BsonDocument("name","John") )

BSON 索引

collection.Indexes.CreateOne(new CreateIndexModel<BsonDocument>(new BsonDocument("name",1)));

要点

  • 直接操作 BsonDocument,更灵活但少了类型安全
  • 适合动态结构或快速原型
  • 与强类型 API 可混合使用,按需选择

36.2 面试题精选

基础题

1. 关系库和文档库/键值库:「最小存储单元」分别长什么样?

题目

各用一句定义「一行/一条文档/一个 KV」在模式与查询上的含义,并各举一个代表产品;最后补一句:选型时除了模型还要看哪两类硬约束。

深入解析
  • 考察点:是否能把「表行 + 固定列」与「嵌套文档 / 裸 KV」区分开,而不是背「NoSQL 快」这类口号。
  • 关系型:最小单元是满足同一 Schema 的一行;关联靠外键与 join;典型 MySQL、PostgreSQL。
  • 文档型:最小单元是可变形状的 BSON/JSON 文档,嵌套数组与子文档是一等公民;典型 MongoDB、Couchbase。
  • 键值型:最小单元是 key → value,value 对引擎往往是透明 blob,复杂条件查询弱;典型 Redis、DynamoDB。
  • 列式 / 图:列族按列组织、适合分析扫少列;图用点边——追问时常用来区分「是不是只会文档和 Redis」。
  • 选型硬约束:一致性与事务边界(能不能接受最终一致、要不要跨文档事务);访问模式(等值、范围、排序、报表、全文)是否匹配引擎能力。
答题示例

核心结论:关系型按「固定列的行」存;文档型按「一棵 JSON 树」存;键值型按「一个 key 对应一块值」存。

展开:MySQL 这类库用表约束把事实拆开;MongoDB 把常一起读的对象嵌在一个文档里;Redis 适合按 key 命中、别指望复杂条件查询。

收口:还要看业务要不要强事务与复杂关联,以及真实查询是不是文档模型兜得住;产品名字不如这两条实在。

参考文章
  • 1.SQL和NoSQL
  • 2.NoSQL种类和特点优点

2. ACID 四个字母各指什么?转账场景里分别挡的是哪类事故?

题目

先按顺序说出英文全称对应的中文习惯译法;再各用半句话说明「如果没有这一条,转账会出什么烂摊子」。最后补一句:MongoDB 能不能说「完全没事务」?

深入解析
  • A(Atomicity,原子性):事务内操作要么全部提交要么全部回滚;烂摊子示例:扣款成功、入账失败,余额对不上。
  • C(Consistency,一致性):事务前后数据库满足约定约束与业务规则(含应用层规则);烂摊子:违反唯一约束、负库存仍可见等「非法中间态」被当成结果。
  • I(Isolation,隔离性):并发事务互相隔离,隔离级别决定能读到多「脏」的中间态;烂摊子:未提交读导致重复扣款决策、统计读到半成品。
  • D(Durability,持久性):已提交写入在故障后仍可恢复;烂摊子:确认支付后进程崩溃,钱款记录消失。
  • MongoDB 边界:多文档事务在较新版本与限定条件下存在,且与副本集、读写关注级别相关;笼统说「NoSQL 没事务」容易在追问里翻车,应改成「默认叙事偏最终一致,事务能力与 SQL 不在同一档位」。
答题示例

核心结论:A 原子性、C 一致性、I 隔离性、D 持久性。

转账口述:原子性防「只扣不加」;一致性防破坏余额规则;隔离性防并发互相读到半截流水;持久性防提交后宕机丢账。

Mongo 一句:别一口咬死「文档库没事务」——有场景支持多文档事务,但和银行核心常用的关系型事务能力不能画等号,要说清版本与范围。

参考文章
  • 1.SQL和NoSQL

3. ObjectId 的 12 字节怎么切?为什么说 _id 排序只有「大致」时间序?

题目

按顺序说出四段各占几字节、各干什么;再解释:同一秒内批量插入时,仅靠 _id 排序能否严格等价于业务上的「创建时间」;最后说工程上该用什么字段做报表时间。

深入解析
  • 结构4+3+2+3 字节——秒级 Unix 时间戳、机器标识、进程 ID、同秒内递增计数器。组合目标是在分布式、多进程下降低碰撞概率。
  • 「大致」原因:排序键的前缀是秒级时间,整体按字节序比较时大体随插入时间增长;同一秒内排序由后 8 字节决定,不保证与真实插入的纳秒级先后一致,更不能当单调时钟。
  • 业务误区:把 _id 当「权威下单时间」或跨系统对齐的时间源;时钟回拨、批量导入、客户端预生成 ObjectId 都会让「时间序」叙事不成立。
  • 工程做法:业务时间用独立字段(如 createdAt),必要时 TTL 索引也用业务语义明确的时间字段,而不是赌 ObjectId
答题示例

结构:4 字节时间戳、3 字节机器、2 字节进程、3 字节计数器,一共 12 字节。

大致:按 _id 排大多能反映先后顺序,但精度到秒,同一秒内谁前谁后看后缀;不能把 _id 当精确创建时间或法律依据时间。

落地:报表、对账、运营统计用明确的 createdAt 之类字段;埋点、战斗日志若批量写入,更不要用 _id 代替业务时间戳。

参考文章
  • 7.MongoDB的ObjectID

4. 复合索引 { a: 1, b: 1 }:什么叫最左前缀?哪种查询「以为能走其实常走不上」?

题目

列出至少两种用到该索引的过滤形态;再举一个不能靠它前缀匹配的典型 filter;最后说要用什么命令验证,以及排序在什么情况下会白建索引。

深入解析
  • 最左前缀:B-tree 复合索引按字段顺序组织;查询条件需从最左字段起形成有效前缀,才能用到索引的左半截。
  • 能用的例子{ a: 1 }{ a: 1, b: 2 }{ a: { $gte: 1 }, b: … }(具体能否走索引仍看规划器与选择性)。
  • 典型反例:仅 { b: 1 } 或仅对 b 排序且无 a 等值/范围锚点——通常无法用 {a,b} 的前缀(除非另有单字段索引或覆盖特殊场景,不能赌)。
  • 排序陷阱sort({ b: 1 }) 且无 a 条件时,往往无法利用 {a,b} 避免内存排序;与 find 同理,顺序是设计出来的,不是「建了就会用」
  • 验证explain("executionStats")winningPlan,盯 IXSCAN / FETCH / SORT 阶段,避免凭感觉答题。
答题示例

最左前缀:索引键从左到右用全了才叫吃到前缀;{a,b} 先服务带 a 的条件。

能用a 定值再查 b,或只约束 a

易错:只查 b、或只对 b sort,却指望 {a,b} 万能——通常不行。

验证:用 explain 看是否 IXSCAN、有没有额外 SORT;线上问题十有八九是条件和索引顺序没对齐。

参考文章
  • 23.MongoDB复合索引

进阶题

1. 垂直扩展与水平扩展各是什么?和 SQL / NoSQL 的常见画像怎么对应?

题目

各用一句话定义两种扩展;各说一个上限或成本痛点;最后举一类典型混合架构(哪类数据放 SQL、哪类放文档或缓存),说明理由。

深入解析
  • 垂直扩展(scale up):更强单机 CPU、内存、磁盘、IO;痛点是硬件天花板、单点故障、大规格迁移窗口与许可成本。
  • 水平扩展(scale out):加节点,通过副本、分片、缓存层分摊读写;痛点是运维与一致性模型复杂、跨分片事务与 join 更痛。
  • 与 SQL / NoSQL 画像:关系型常与强一致、复杂查询绑定,历史路径上先榨干单机再做读写分离;文档、键值、宽列产品形态更常从一开始就为分片与海量写入设计(具体仍以产品为准)。
  • 混合架构:支付、库存、账号核心表在 SQL;玩家存档、行为日志、配置快照在 MongoDB;Session、排行榜、限流在 Redis——用一致性要求与访问模式切边界,而不是「全盘 NoSQL」。
答题示例

定义:垂直扩展是把一台机器加粗;水平扩展是多台机器一起扛。

痛点:垂直扩展撞到单机天花板和迁移成本;水平扩展换运维复杂度和数据分布设计。

选型口语:强一致、复杂报表的核心表常见先垂直 + 读写分离;用户量与写入顶穿单机时,半结构化业务数据更常走分片文档库,热点再叠 Redis。

混合例子:充值、扣钻走 SQL;存档、战斗回放元数据走 Mongo;排行榜底表走 Redis——各层一致性要求不一样。

参考文章
  • 1.SQL和NoSQL

2. 键值、列式、文档三类:各举一个「最划算」的负载,再各举一个「明显别选」的反例。

题目

九句话内答完(每类三句:适合 / 不适合 / 代表产品任选其一);追问准备:列式为什么不适合高并发小行更新?

深入解析
  • 键值:划算在 Session、缓存、计数器、排行榜、特征向量按 key 覆盖;不划算在多维条件检索、报表、复杂关联;代表 Redis、Memcached、DynamoDB。
  • 列式:划算在 OLAP、数仓、扫海量行只取少数列;不划算在 OLTP 式高频随机更新与小事务;代表 HBase、Cassandra、Bigtable。
  • 文档:划算在用户资料、内容、订单快照、游戏存档 JSON;不划算在多表星型模型报表、强依赖跨文档复杂 join 且不愿冗余;代表 MongoDB、CouchDB、Couchbase。
  • 追问根因:列式存储按列压缩与批量读优化,行级反复改写会破坏压缩与存储局部性,写入路径与关系型行存完全不同。
答题示例

键值:按 key 读写极快,适合缓存、计数器;复杂查询别硬上;Redis 最常被点到。

列式:扫几列分析、报表香;当高并发订单库会写爆;HBase、Cassandra 那一路。

文档:业务对象是树状 JSON 时顺手;要星型报表、到处 join 不如关系型;MongoDB 是常见代表。

收口:先问读写模式与一致性,再选存储模型;没有「一种 NoSQL 吃天下」。

参考文章
  • 2.NoSQL种类和特点优点

3. 聚合管道 aggregate([...]) 在模型上是什么?$match 为什么要尽量靠前?

题目

用「数组 + 阶段」两句话讲清管道语义;举一条典型阶段链(至少四个阶段名);再从「文档数、CPU、内存上限」三个角度解释提前 $match 的收益。

深入解析
  • 模型aggregate 接收阶段数组,每个阶段消费上游文档流、输出新流;顺序有语义,不是无序集合。
  • find 关系$match 使用的查询算子与 find 同族,但在管道里只是一段,后面还可 $lookup$facet 等继续变形。
  • 提前过滤收益:后续 $group$sort$lookup 处理的文档数下降,降低 CPU、内存与磁盘溢出概率;大集合上这是性能分水岭。
  • 内存边界:排序、分组等阶段受内存限制,超标需 allowDiskUse 或改索引与管道顺序;把 $match 顶在前面是「先瘦身再折腾」的基本功。
  • 骨架记忆$match$group / $sort$skip / $limit$project,按题裁剪。
答题示例

一句话模型aggregate 里是流水线,上一阶段的输出文档进下一阶段。

典型链$match 过滤 → $group 统计 → $sort 排序 → $limit 取 TopN,中间可插 $project 裁剪字段。

为什么要早 match:先扔掉无关文档,后面分组排序的数据量小,省 CPU、省内存;管道阶段有内存门槛,先瘦身再聚合是常规答法。

参考文章
  • 16.MongoDB聚合查询概念
  • 17.MongoDB过滤文档聚合查询

4. 深分页里 skip 为什么贵?用 _id 做游标分页时 filter 怎么写?

题目

用「引擎仍要扫描/丢弃多少文档」说清 skip 的复杂度直觉;写出一类基于 _id Strictly Increasing 假设的下一页查询形态(可用伪代码);最后点出并发插入删除下产品侧要接受什么现象。

深入解析
  • skip 成本:即使只返回一页,skip(n) 仍要遍历并丢弃前 n 条匹配文档;n 增大时 CPU 与 IO 近似线性变差,索引也只能减轻而不能魔法消除「跳过」本身。
  • 游标分页思路:记住上一页最后一条的 _id(或复合排序键),下一页用大于该键的范围条件接力 limit,避免重复 skip
  • 伪代码形态find({ _id: { $gt: lastId } }).sort({ _id: 1 }).limit(pageSize);若按业务字段排序,需用「排序键 + _id」组成稳定排序键防重复。
  • 并发副作用:插入可能导致「跳读」或「重复」;删除可能导致当前页条数不足;需产品容忍或引入版本号、快照类设计。
答题示例

skip:数据库仍然要把前面 N 条走过一遍再扔掉,N 越大越像自虐。

游标:记住这页最后一条的 _id,下一页用 { _id: { $gt: lastId } } 接龙,再 sort + limit

稳定排序:如果按时间排,常用「时间 + _id」双键,避免同毫秒冲突。

并发:边翻边写会跳行或重复,产品要接受或做补偿,别假装静态集合。

参考文章
  • 15.MongoDB分页查询

深度题

1. 别背 CAP:用「读到的后果」区分强一致与最终一致,各举一例。

题目

各举一个必须强一致的业务(说明错一致模型会怎样);再举一个可最终一致的业务(说明能容忍多长窗口、错模型主要损什么);最后一句落到「怎么跟产品对齐指标」。

深入解析
  • 强一致叙事:用户读到的就是已提交的最新事实;错用最终一致在余额、库存、道具扣减、防重复支付上可能造成资损、超卖、重复发货,属于 P0 级事故。
  • 最终一致叙事:短时间读到旧值,但在可接受时间内收敛;点赞数、在线人数、推荐列表、非关键排行榜,错模型多是体验问题,很少直接等价于资金错误。
  • 落地方法:与产品/风控对齐「可接受的不一致窗口、是否允许读到旧值、失败是否可补偿」;再决定缓存、读写分离、事务、幂等与对账——用后果表驱动架构,而不是先选 buzzword
  • 追问防守:能说出「强一致不等于只用 SQL」「最终一致也要幂等与监控」,分数会明显高于空喊 CAP。
答题示例

强一致例子:点券、付费货币、限量道具库存;读到旧库存会超卖,读到旧余额会重复消费,这是钱的问题。

最终一致例子:公会点赞数、世界频道热度、推荐列表;几秒旧一点能接受,主要损体验。

对齐方式:先问「错读一秒会不会赔钱」,再定缓存与副本读;能赔偿与对账的业务才敢放宽。

参考文章
  • 1.SQL和NoSQL

2. 关系型范式化 vs 文档嵌套与冗余:从读、写、改模式各说一个权衡。

题目

各答三点——读路径(几次往返、是否 join)、写一致性(一份事实更新几处)、模式演进(加字段/拆表的代价);最后用游戏业务举一个「拆表合理」与一个「嵌套合理」的例子。

深入解析
  • 关系型:读路径通过 join 拼视图,索引设计成熟时报表强;写一致性单点更新清晰;模式演进靠迁移脚本,强约束变更成本高但边界清楚。
  • 文档型:读路径可把热点聚合嵌在一个文档,减少往返与跨分片 join;写一致性要处理冗余字段同步、部分更新与文档体积膨胀;模式演进灵活但对团队纪律要求高(版本字段、兼容读写)。
  • 常见追问:「MongoDB 为什么不全放一个集合」——单文档 16MB 上限、索引与写放大、热点行竞争、跨实体生命周期不同,都是拆文档边界理由。
  • 游戏侧例:账号安全、支付流水适合关系型或强约束存储;单局内装备列表、天赋树快照适合嵌套文档;全服邮件模板与玩家邮箱列表常拆集合并受控冗余。
答题示例

关系型:读靠 join,写改一行是一处事实;改表要迁移,但约束清楚。

文档型:读把一次界面要用的嵌在一起,写要管冗余是否同步;加字段灵活,但要约定兼容策略。

游戏例:充值订单、风控流水适合 SQL;单局背包、技能树嵌在玩家文档里更顺;别把全服配置和每个玩家存档塞进同一个大文档。

参考文章
  • 1.SQL和NoSQL
  • 2.NoSQL种类和特点优点

3. 开发机一直用 bindIp: 127.0.0.1,上线要对外开放:风险链怎么讲?最小加固清单列哪几项?

题目

按「监听地址 → 网络可达性 → 认证与账号 → 秘密管理」四层口述;每层各说一个具体失误(例如绑到 0.0.0.0 且未开 authorization);清单不少于五项,其中必须包含防火墙/安全组与独立业务账号。

深入解析
  • 监听与暴露127.0.0.1 仅本机回环;改为 0.0.0.0 或公网 IP 即扩大监听面,需与安全组、VPC、iptables 同步收紧,否则等于在公网吆喝端口
  • 匿名访问:未启用 authorization 时,能连上的人往往能读写;内网误配路由或 SSRF 时同样危险。
  • 账号与最小权限:管理员与普通业务库用户分离;应用连接串使用仅必要权限的账号,避免 root 写进仓库或配置中心明文扩散。
  • 秘密与传输:密码轮换、TLS(若跨公网或合规要求)、审计日志与备份可用性同属「上线检查表」。
  • 配置面netsecuritysystemLogstorage 要一起看,只改端口不改认证是常见事故模板。
答题示例

风险链:先看清监听的是本机还是全网;再看过防火墙有没有洞;再看有没有开认证;最后看连接串里是不是管理员账号裸奔。

典型失误0.0.0.0 + 无认证 + 公网安全组全开,等于送库。

最小清单:只监听内网网卡;安全组白名单收口;authorization: enabled;业务独立账号最小权限;强密码与轮换;日志与备份可用;连接串不进 Git。

参考文章
  • 4.MongoDB配置文件
  • 6.MongoDB连接和启用认证

4. 稀疏索引与部分索引各解决什么数据形态?为何不能在同一条索引上同时写 sparsepartialFilterExpression

题目

各用「哪些文档会进索引」一句话定义;各举一个查询侧注意点($exists、与 partial 谓词对齐);最后用「语义重叠 / 规划器复杂度」解释禁混开,并点一句部分索引要配合什么样的 filter 才容易被选中。

深入解析
  • 稀疏 sparse:索引字段缺失的文档不进入索引;适合字段可有可无、查询常与 $exists 搭配的场景;与唯一索引组合可实现「仅对有字段文档唯一」一类需求(仍以官方语义为准)。
  • 部分 partialFilterExpression:仅满足谓词的文档进入索引,可表达比「字段存在」更细的业务子集(如 status: "active");常与唯一约束组合做「子集唯一」。
  • 查询匹配:部分索引要求过滤条件能蕴含一致于 partialFilterExpression,否则规划器可能放弃该索引;这是面试里区分「建了索引」与「会用索引」的细节。
  • 禁混开原因:两者都在缩小索引中文档子集,语义重叠,组合规则复杂;服务端直接拒绝同开,强迫二选一,通常 partial 表达力更强
  • 治理:避免为同一访问路径重复堆叠多条「半索引」,定期用 explain 与慢查询核对。
答题示例

稀疏:没有该字段的文档不进索引,适合可选字段。

部分:只把满足条件的文档放进索引,比如只要活跃用户的索引。

查询侧:查条件要和 partial 的谓词对得上,否则可能根本不用这条索引。

禁混开:两个开关都在「缩小谁进索引」,叠在一起语义重复,官方直接不让配;一般优先 partial。

落地:建完用 explain 验证,别假设「建了就会走」。

参考文章
  • 27.MongoDB稀疏索引
  • 29.MongoDB部分索引


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏