Appearance
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/test13. 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的最佳实践有哪些?
答案:
- 根据查询模式创建索引。
- 使用合适的数据模型(嵌入或引用)。
- 使用副本集实现高可用性。
- 使用分片实现水平扩展。
- 定期备份数据。
- 监控数据库性能。
- 优化慢查询。
- 使用写关注和读关注控制数据一致性。
- 启用认证保护数据库安全。
- 使用压缩减少存储空间。
