Skip to content

MongoDB面试题

1. MongoDB的基本概念

问题:什么是MongoDB?

答案

  • MongoDB:一个基于文档的NoSQL数据库。
  • 特点
    • 文档存储
    • 灵活的模式
    • 高性能
    • 高可用性
    • 易扩展性

2. MongoDB的数据模型

问题:MongoDB的数据模型有哪些?

答案

  • 文档:MongoDB的基本数据单元,使用BSON格式。
  • 集合:文档的集合,类似于关系型数据库的表。
  • 数据库:集合的集合,类似于关系型数据库的数据库。

示例

javascript
// 文档示例
{
  "_id": ObjectId("507f1f77bcf86cd799439011"),
  "name": "John Doe",
  "age": 30,
  "email": "john@example.com",
  "address": {
    "street": "123 Main St",
    "city": "New York",
    "state": "NY"
  }
}

3. MongoDB的数据类型

问题:MongoDB支持哪些数据类型?

答案

  • 字符串:String
  • 数值:Number(Int32、Int64、Double)
  • 布尔值:Boolean
  • 日期:Date
  • 空值:Null
  • 数组:Array
  • 对象:Object
  • ObjectId:ObjectId
  • 二进制数据:BinData
  • 代码:JavaScript
  • 正则表达式:Regex
  • 时间戳:Timestamp
  • 最小键:MinKey
  • 最大键:MaxKey

4. MongoDB的CRUD操作

问题:如何进行CRUD操作?

答案

javascript
// 插入文档
db.users.insertOne({
  name: "John Doe",
  age: 30,
  email: "john@example.com"
});

// 查询文档
db.users.find({ age: { $gt: 25 } });

// 更新文档
db.users.updateOne(
  { name: "John Doe" },
  { $set: { age: 31 } }
);

// 删除文档
db.users.deleteOne({ name: "John Doe" });

5. MongoDB的查询操作

问题:MongoDB支持哪些查询操作?

答案

  • 比较操作符
    • $eq:等于
    • $gt:大于
    • $gte:大于等于
    • $lt:小于
    • $lte:小于等于
    • $ne:不等于
  • 逻辑操作符
    • $and:与
    • $or:或
    • $not:非
    • $nor:既不也不
  • 元素操作符
    • $exists:字段是否存在
    • $type:字段类型
  • 数组操作符
    • $all:包含所有元素
    • $elemMatch:数组元素匹配
    • $size:数组大小

示例

javascript
// 比较操作
db.users.find({ age: { $gt: 25 } });

// 逻辑操作
db.users.find({ $or: [{ age: { $gt: 30 } }, { age: { $lt: 20 } }] });

// 数组操作
db.users.find({ tags: { $all: ["java", "mongodb"] } });

6. MongoDB的索引

问题:如何创建索引?

答案

javascript
// 创建单字段索引
db.users.createIndex({ name: 1 });

// 创建复合索引
db.users.createIndex({ name: 1, age: -1 });

// 创建唯一索引
db.users.createIndex({ email: 1 }, { unique: true });

// 创建文本索引
db.articles.createIndex({ content: "text" });

// 查看索引
db.users.getIndexes();

// 删除索引
db.users.dropIndex({ name: 1 });

7. MongoDB的聚合

问题:如何使用聚合?

答案

javascript
// 聚合示例
db.users.aggregate([
  // 匹配阶段
  { $match: { age: { $gte: 18 } } },
  // 分组阶段
  { $group: { _id: "$city", count: { $sum: 1 } } },
  // 排序阶段
  { $sort: { count: -1 } },
  // 限制阶段
  { $limit: 10 }
]);

// 常用聚合操作
// $match:过滤文档
// $group:分组
// $sort:排序
// $limit:限制结果数量
// $skip:跳过结果
// $project:选择字段
// $unwind:展开数组
// $lookup:左连接

8. MongoDB的副本集

问题:什么是副本集?

答案

  • 副本集:MongoDB的高可用性解决方案,由多个MongoDB实例组成。
  • 角色
    • 主节点(Primary):处理所有写操作
    • 从节点(Secondary):复制主节点的数据
    • 仲裁节点(Arbiter):不存储数据,只参与选举

特点

  • 自动故障转移
  • 数据冗余
  • 读写分离

9. MongoDB的分片

问题:什么是分片?

答案

  • 分片:MongoDB的水平扩展解决方案,将数据分散到多个服务器。
  • 组件
    • 配置服务器(Config Servers):存储集群元数据
    • 分片服务器(Shards):存储数据
    • 查询路由器(Mongos):路由客户端请求

特点

  • 支持大数据量
  • 支持高吞吐量
  • 自动平衡数据

10. MongoDB的事务

问题:MongoDB支持事务吗?

答案

  • 支持:MongoDB 4.0+支持多文档ACID事务。
  • 使用场景
    • 需要保证数据一致性的场景
    • 需要跨多个集合操作的场景

示例

javascript
// 事务示例
const session = db.getMongo().startSession();
session.startTransaction();

try {
  const usersCollection = session.getDatabase('test').users;
  const ordersCollection = session.getDatabase('test').orders;
  
  usersCollection.updateOne(
    { _id: userId },
    { $inc: { balance: -amount } },
    { session }
  );
  
  ordersCollection.insertOne(
    { userId, amount, date: new Date() },
    { session }
  );
  
  session.commitTransaction();
} catch (error) {
  session.abortTransaction();
  throw error;
} finally {
  session.endSession();
}

11. MongoDB的索引优化

问题:如何优化索引?

答案

  • 创建合适的索引
    • 为常用查询字段创建索引
    • 为排序字段创建索引
  • 使用复合索引
    • 将常用查询条件组合成复合索引
  • 避免全表扫描
    • 使用索引查询
  • 定期分析查询
    • 使用explain分析查询计划

示例

javascript
// 分析查询计划
db.users.find({ age: { $gt: 25 } }).explain();

// 查看索引使用情况
db.users.aggregate([
  { $indexStats: {} }
]);

12. MongoDB的备份与恢复

问题:如何备份和恢复MongoDB?

答案

  • mongodump:逻辑备份工具。
  • mongorestore:逻辑恢复工具。
  • 文件系统快照:物理备份。

示例

bash
# 备份
mongodump --host localhost --port 27017 --db test --out /backup

# 恢复
mongorestore --host localhost --port 27017 --db test /backup/test

13. MongoDB的监控

问题:如何监控MongoDB?

答案

  • 监控工具
    • MongoDB Compass
    • MongoDB Ops Manager
    • Cloud Manager
    • Prometheus + Grafana
  • 监控指标
    • 连接数
    • 操作数
    • 内存使用
    • 磁盘使用
    • 慢查询

14. MongoDB的慢查询

问题:如何分析慢查询?

答案

javascript
// 启用慢查询日志
db.setProfilingLevel(1, { slowms: 100 });

// 查看慢查询
db.system.profile.find().sort({ millis: -1 }).limit(10);

// 分析查询计划
db.users.find({ age: { $gt: 25 } }).explain("executionStats");

15. MongoDB的数据建模

问题:如何设计MongoDB的数据模型?

答案

  • 嵌入模式
    • 将相关数据嵌入到同一个文档中
    • 适合一对一、一对多关系
  • 引用模式
    • 使用引用关联不同文档
    • 适合多对多关系

示例

javascript
// 嵌入模式
{
  "_id": ObjectId("507f1f77bcf86cd799439011"),
  "name": "John Doe",
  "addresses": [
    { "street": "123 Main St", "city": "New York" },
    { "street": "456 Oak Ave", "city": "Boston" }
  ]
}

// 引用模式
{
  "_id": ObjectId("507f1f77bcf86cd799439011"),
  "name": "John Doe",
  "addressIds": [
    ObjectId("507f1f77bcf86cd799439012"),
    ObjectId("507f1f77bcf86cd799439013")
  ]
}

16. MongoDB的GridFS

问题:什么是GridFS?

答案

  • GridFS:MongoDB的文件存储规范,用于存储和检索大文件。
  • 特点
    • 支持大文件(>16MB)
    • 自动分块存储
    • 支持文件元数据

示例

javascript
// 存储文件
const bucket = new mongoose.mongo.GridFSBucket(db);
const uploadStream = bucket.openUploadStream('example.txt');
fs.createReadStream('example.txt').pipe(uploadStream);

// 读取文件
const downloadStream = bucket.openDownloadStreamByName('example.txt');
downloadStream.pipe(fs.createWriteStream('example.txt'));

17. MongoDB的变更流

问题:什么是变更流?

答案

  • 变更流:MongoDB 3.6+提供的实时数据变更通知功能。
  • 作用
    • 实时监控数据变更
    • 实现数据同步
    • 实现缓存更新

示例

javascript
// 监听变更
const changeStream = db.collection('users').watch();

changeStream.on('change', (change) => {
  console.log('Change:', change);
});

18. MongoDB的连接池

问题:如何配置连接池?

答案

javascript
// 配置连接池
const MongoClient = require('mongodb').MongoClient;
const uri = 'mongodb://localhost:27017';

const client = new MongoClient(uri, {
  maxPoolSize: 100,
  minPoolSize: 10,
  maxIdleTimeMS: 30000,
  waitQueueTimeoutMS: 5000
});

await client.connect();

19. MongoDB的写关注

问题:什么是写关注?

答案

  • 写关注:控制写操作确认级别的选项。
  • 级别
    • w:1:默认,主节点确认
    • w:majority:大多数节点确认
    • w:0:不等待确认
    • j:true:写入日志

示例

javascript
// 设置写关注
db.users.insertOne(
  { name: "John Doe" },
  { writeConcern: { w: "majority", j: true } }
);

20. MongoDB的读关注

问题:什么是读关注?

答案

  • 读关注:控制读操作返回数据的级别。
  • 级别
    • local:返回本地数据
    • majority:返回大多数节点的数据
    • linearizable:返回线性一致的数据

示例

javascript
// 设置读关注
db.users.find({ name: "John Doe" }).readConcern("majority");

21. MongoDB的读写分离

问题:如何实现读写分离?

答案

javascript
// 配置读写分离
const client = new MongoClient(uri, {
  readPreference: 'secondary',
  readConcern: { level: 'majority' },
  writeConcern: { w: 'majority' }
});

// 读偏好选项
// primary:只从主节点读取
// primaryPreferred:优先从主节点读取
// secondary:只从从节点读取
// secondaryPreferred:优先从从节点读取
// nearest:从最近的节点读取

22. MongoDB的安全管理

问题:如何管理MongoDB安全?

答案

  • 认证
    • 启用认证
    • 创建用户
    • 分配角色
  • 授权
    • 内置角色
    • 自定义角色
  • 加密
    • 传输加密(TLS/SSL)
    • 静态加密

示例

javascript
// 创建用户
db.createUser({
  user: "admin",
  pwd: "password",
  roles: [
    { role: "userAdminAnyDatabase", db: "admin" },
    { role: "readWriteAnyDatabase", db: "admin" }
  ]
});

23. MongoDB的性能优化

问题:如何优化MongoDB性能?

答案

  • 索引优化
    • 创建合适的索引
    • 使用复合索引
  • 查询优化
    • 避免全表扫描
    • 使用投影减少返回数据
  • 硬件优化
    • 使用SSD
    • 增加内存
  • 架构优化
    • 使用副本集
    • 使用分片

24. MongoDB的常见问题

问题:MongoDB常见问题有哪些?

答案

  • 内存问题
    • 工作集过大
    • 内存不足
  • 磁盘问题
    • 磁盘空间不足
    • 磁盘IO瓶颈
  • 性能问题
    • 慢查询
    • 索引不当
  • 连接问题
    • 连接数过多
    • 连接超时

25. MongoDB的最佳实践

问题:使用MongoDB的最佳实践有哪些?

答案

  • 根据查询模式创建索引。
  • 使用合适的数据模型(嵌入或引用)。
  • 使用副本集实现高可用性。
  • 使用分片实现水平扩展。
  • 定期备份数据。
  • 监控数据库性能。
  • 优化慢查询。
  • 使用写关注和读关注控制数据一致性。
  • 启用认证保护数据库安全。
  • 使用压缩减少存储空间。