MongoDB面试题分类整理

MongoDB面试题分类整理

一、基础概念

1. MongoDB是什么?与传统关系型数据库有什么区别?

答案
MongoDB是一个文档型NoSQL数据库,它用类似JSON的BSON格式存储数据。与传统关系型数据库(RDBMS)的主要区别:

  • 数据模型:MongoDB是文档模型,RDBMS是表模型
  • Schema:MongoDB是动态Schema(不需要预先定义表结构),RDBMS是固定Schema
  • 扩展方式:MongoDB更容易水平扩展(分片),RDBMS通常垂直扩展
  • 事务支持:早期MongoDB不支持多文档事务,现在已支持(4.0+版本)
  • JOIN操作:MongoDB用$lookup模拟JOIN,性能不如RDBMS的JOIN

原理:想象MongoDB像一个大的文件柜,每个文档就是一个独立的文件,你可以随时往里面添加各种格式的文件。而RDBMS像Excel表格,必须预先定义好列名和数据类型。

2. 解释MongoDB中的文档、集合和数据库

答案

  • 文档(Document):相当于RDBMS中的一行记录,用BSON格式存储(类似JSON)
  • 集合(Collection):相当于RDBMS中的表,是一组文档的容器
  • 数据库(Database):一组集合的容器,一个MongoDB实例可以包含多个数据库

原理:可以想象MongoDB的结构像一本书:

  • 数据库=书
  • 集合=书的章节
  • 文档=章节中的段落

二、CRUD操作

1. MongoDB如何插入文档?

答案

// 插入单个文档
db.collection.insertOne({name: "张三", age: 25})

// 插入多个文档
db.collection.insertMany([
  {name: "李四", age: 30},
  {name: "王五", age: 28}
])

原理:MongoDB接收到插入命令后,会先将数据转换为BSON格式,然后写入内存和磁盘。默认情况下,写入操作会等待磁盘确认后才返回成功。

2. 如何更新文档?set和unset有什么区别?

答案

// 更新单个文档
db.collection.updateOne(
  {name: "张三"}, 
  {$set: {age: 26}}
)

// $set用于设置字段值
db.collection.updateOne(
  {name: "张三"}, 
  {$set: {address: "北京"}}
)

// $unset用于删除字段
db.collection.updateOne(
  {name: "张三"}, 
  {$unset: {address: ""}}
)

原理:set就像给文档打补丁,只修改指定的字段,其他字段不变。unset则是从文档中移除指定字段。如果不使用$set而直接更新,整个文档会被替换。

三、索引与性能优化

1. MongoDB索引有哪些类型?

答案

  • 单字段索引:在单个字段上创建的索引
  • 复合索引:在多个字段上创建的索引
  • 多键索引:为数组字段中的每个元素创建索引
  • 文本索引:支持字符串内容的全文搜索
  • 地理空间索引:支持地理位置查询
  • 哈希索引:将字段值哈希后创建索引
  • TTL索引:自动删除过期的文档
  • 唯一索引:确保字段值唯一

原理:索引就像书的目录,可以快速找到内容而不需要逐页查找。MongoDB使用B树数据结构存储索引,不同类型的索引针对不同的查询场景优化。

2. 如何分析查询性能?

答案

// 使用explain()分析查询
db.collection.find({name: "张三"}).explain("executionStats")

// 主要关注以下指标:
// - executionTimeMillis:执行时间(毫秒)
// - totalDocsExamined:扫描的文档数
// - totalKeysExamined:扫描的索引键数
// - stage:查询执行阶段(COLLSCAN表示全表扫描,IXSCAN表示索引扫描)

原理:explain()就像MongoDB的X光机,可以查看查询执行的内部过程。好的查询应该尽量减少扫描的文档数,尽量使用索引扫描而非全表扫描。

四、聚合框架

1. 解释MongoDB的聚合管道

答案
聚合管道是一系列数据处理阶段,文档依次通过这些阶段被处理。常用阶段包括:

  • $match:过滤文档(类似WHERE)
  • $project:选择/重命名字段(类似SELECT)
  • $group:分组聚合(类似GROUP BY)
  • $sort:排序(类似ORDER BY)
  • limit/skip:分页
  • $lookup:关联查询(类似JOIN)

示例

db.orders.aggregate([
  {$match: {status: "completed"}},
  {$group: {_id: "$customer", total: {$sum: "$amount"}}},
  {$sort: {total: -1}},
  {$limit: 10}
])

原理:想象聚合管道像工厂的流水线,文档是产品,每个阶段是一个工作站,产品经过每个工作站都会被加工处理,最终得到想要的结果。

2. $lookup如何工作?有什么限制?

答案
$lookup实现类似SQL的LEFT OUTER JOIN:

db.orders.aggregate([
  {
    $lookup: {
      from: "customers",       // 要关联的集合
      localField: "customerId", // 本地字段
      foreignField: "_id",      // 外部集合字段
      as: "customerInfo"        // 输出数组字段
    }
  }
])

限制

  1. 关联的两个集合必须在同一数据库中
  2. 性能可能不如RDBMS的JOIN高效
  3. 大数据集可能导致内存问题

原理:$lookup就像你去图书馆借书,先查自己的借书卡(localField),然后去书库(from)找对应的书(foreignField),最后把找到的书信息(customerInfo)带回来。

五、复制集(Replica Set)

1. 什么是MongoDB复制集?有什么作用?

答案
复制集是一组维护相同数据集的MongoDB实例,包含:

  • 1个主节点(Primary):处理所有写操作
  • 1个或多个从节点(Secondary):复制主节点数据
  • 可选的仲裁节点(Arbiter):不存储数据,只参与选举

作用

  1. 高可用性:主节点故障时自动故障转移
  2. 数据冗余:多副本防止数据丢失
  3. 读写分离:从节点可以处理读请求

原理:复制集就像公司里的团队,主节点是经理(负责决策和写操作),从节点是员工(复制经理的决定),当经理休假时,员工们会选举新的经理。

2. 解释MongoDB的选举机制

答案
当主节点不可用时(心跳超时),从节点会发起选举。选举规则:

  1. 获得大多数成员投票的节点成为新主节点
  2. 优先级高的节点更可能成为主节点
  3. 数据最新的节点优先
  4. 仲裁节点只参与投票,不存储数据

原理:选举就像班级选班长,同学们(节点)投票,得票最多且符合条件(成绩好/数据新)的同学当选。大多数同学(超过半数)必须参与投票才有效。

六、分片(Sharding)

1. 什么是分片?为什么要分片?

答案
分片是将大数据集水平分割到多个MongoDB实例(分片)上的方法。

为什么要分片

  1. 数据量超过单机存储容量
  2. 读写吞吐量超过单机处理能力
  3. 想实现地理分布的数据存储

分片组件

  • 分片(Shard):存储实际数据
  • 配置服务器(Config Server):存储集群元数据
  • 查询路由器(mongos):路由查询到正确的分片

原理:分片就像把一本大百科全书拆分成多卷,每卷放在不同的书架上。目录(配置服务器)告诉你哪部分内容在哪卷,图书管理员(mongos)帮你找到需要的卷。

2. 解释分片键的选择策略

答案
分片键的选择至关重要,好的分片键应该:

  1. 基数高:有很多不同的值(如用户ID)
  2. 写分布均匀:避免热点(所有写操作集中到一个分片)
  3. 匹配查询模式:常用查询条件应包含分片键

常见策略

  • 哈希分片:均匀分布但无法范围查询
  • 范围分片:支持范围查询但可能导致数据分布不均
  • 复合分片:结合多个字段

原理:选择分片键就像选择如何切蛋糕。如果按水果种类切(范围分片),草莓部分可能很大而蓝莓部分很小;如果随机切(哈希分片),每块大小差不多但找不到特定水果的位置。

七、事务与一致性

1. MongoDB如何实现多文档事务?

答案
从MongoDB 4.0开始支持多文档事务:

session.startTransaction()
try {
  db.accounts.updateOne({name: "A"}, {$inc: {balance: -100}}, {session})
  db.accounts.updateOne({name: "B"}, {$inc: {balance: 100}}, {session})
  session.commitTransaction()
} catch (error) {
  session.abortTransaction()
}

限制

  1. 事务中的操作必须属于同一个分片(分片集群中)
  2. 事务最大运行时间有限制(默认60秒)
  3. 会影响性能

原理:MongoDB事务就像银行转账操作,要么两个账户都更新成功,要么都失败回滚。内部使用快照隔离机制,保证事务看到一致的数据视图。

2. MongoDB的写关注(Write Concern)和读偏好(Read Preference)是什么?

答案
​写关注​​:控制写操作的确认级别

// 写入主节点后确认
db.collection.insert({...}, {writeConcern: {w: 1}})

// 写入大多数节点后确认
db.collection.insert({...}, {writeConcern: {w: "majority"}})

读偏好:控制从哪个节点读取

// 从主节点读取(默认)
db.collection.find().readPref("primary")

// 从从节点读取
db.collection.find().readPref("secondary")

原理:写关注就像寄信,你可以选择"投递到邮箱"(w:1)就确认,或者"对方签收"(w:“majority”)才确认。读偏好就像读书,你可以选择读原版(primary)或复印件(secondary)。

八、安全与运维

1. MongoDB如何实现身份验证和授权?

答案
​身份验证​​:

  1. 启用认证:启动时加--auth参数
  2. 创建用户:
db.createUser({
  user: "admin",
  pwd: "password",
  roles: ["userAdminAnyDatabase"]
})

授权
基于角色的访问控制(RBAC),常用内置角色:

  • read:只读
  • readWrite:读写
  • dbAdmin:数据库管理
  • userAdmin:用户管理
  • clusterAdmin:集群管理

原理:MongoDB的安全机制像公司的门禁系统,用户需要用户名密码(身份验证)才能进入,然后根据工牌(角色)决定能进入哪些区域(数据库)和做什么操作(权限)。

2. 如何备份和恢复MongoDB数据?

答案
​备份​​:

  1. mongodump工具:
mongodump --uri="mongodb://user:password@host:port/db" --out=/backup/path
  1. 文件系统快照(需要存储引擎支持)
mongorestore --uri="mongodb://user:password@host:port/db" /backup/path

原理:mongodump像复印机,把数据库内容复制到文件;mongorestore像扫描仪,把文件内容重新导入数据库。对于大数据集,文件系统快照效率更高(像给数据库拍照片)。

九、高级特性

1. 什么是Change Stream?如何使用?

答案
Change Stream允许应用程序实时监听数据库变更:

const changeStream = db.collection.watch()

changeStream.on("change", (change) => {
  console.log("Change detected:", change)
})

使用场景

  1. 实时数据同步
  2. 事件驱动架构
  3. 数据变更审计

原理:Change Stream像数据库的"消息通知",当数据发生变化时,会推送变更事件给监听者。底层使用oplog(操作日志)实现。

2. MongoDB的存储引擎有哪些?有什么区别?

答案
主要存储引擎:

  1. WiredTiger(默认):
    • 支持文档级并发控制
    • 支持压缩
    • 使用B+树存储数据
  2. In-Memory(企业版):
    • 所有数据存储在内存中
    • 极高性能但不持久化
  3. MMAPv1(已废弃):
    • MongoDB早期引擎
    • 集合级锁,性能较差

原理:存储引擎就像汽车的发动机,WiredTiger是现代的涡轮增压发动机(高效节能),In-Memory是赛车发动机(极快但不耐用),MMAPv1是老式发动机(已淘汰)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值