MongoDB基础知识
目录
- 基础篇
- 进阶篇
- 应用篇
- 十五、MongoDB性能诊断
- 十六、MongoDB数据迁移
- 十七、MongoDB应用开发最佳实践
- 十八、MongoDB运维管理
- 十九、MongoDB常见应用场景示例
- 二十、MongoDB与Java集成
- [二十一、MongoDB与Spring Boot集成](#二十一、MongoDB与Spring Boot集成)
- 二十二、MongoDB与Docker部署
- 最佳实践篇
基础篇
一、MongoDB入门指南(零基础必读)
1.1 MongoDB是什么?
把MongoDB想象成一个超级大的Excel表格本:
- 数据库(Database)就像一个Excel工作簿
- 集合(Collection)就像工作簿中的工作表
- 文档(Document)就像工作表中的一行数据
- 字段(Field)就像表格中的列
与传统MySQL数据库相比:
- MySQL要求表格结构固定(每列的类型必须一致)
- MongoDB更灵活,同一个集合中的文档可以有不同的字段
1.2 为什么选择MongoDB?
-
容易上手
- 数据格式类似JSON,对开发者友好
- 不需要设计复杂的表关系
- 存储格式灵活,想存什么就存什么
-
适合的应用场景
- 存储网站用户数据
- 存储商品评论信息
- 记录系统日志
- 存储游戏数据
1.3 基础操作入门示例
1. 数据库操作
javascript
// 创建/切换到"我的数据库"
use mydb
// 查看有哪些数据库
show dbs
// 删除当前使用的数据库
db.dropDatabase()
2. 集合操作
javascript
// 创建"用户信息"集合
db.createCollection("用户信息")
// 查看所有集合
show collections
// 删除"用户信息"集合
db.用户信息.drop()
3. 实用操作示例
添加用户信息
javascript
// 添加一个用户
db.用户信息.insertOne({
姓名: "小明",
年龄: 18,
爱好: ["打游戏", "看电影"],
联系方式: {
手机: "13812345678",
邮箱: "[email protected]"
}
})
查询用户信息
javascript
// 查找所有用户
db.用户信息.find()
// 查找叫"小明"的用户
db.用户信息.find({姓名: "小明"})
// 查找18岁的用户
db.用户信息.find({年龄: 18})
// 查找大于18岁的用户
db.用户信息.find({年龄: {$gt: 18}})
1.4 新手常见问题解决
1. 数据重复问题
javascript
// 设置用户名不能重复
db.users.createIndex({用户名: 1}, {unique: true})
// 检查用户名是否存在
const userExists = db.users.findOne({用户名: "xiaoming"})
if (!userExists) {
// 可以注册
}
2. 查询速度慢问题
javascript
// 为常用查询字段创建索引
db.users.createIndex({年龄: 1})
db.users.createIndex({注册时间: 1})
// 只返回需要的字段
db.users.find(
{年龄: {$gt: 18}},
{用户名: 1, 年龄: 1, _id: 0}
)
1.5 新手使用建议
-
命名建议
- 数据库名用小写字母
- 集合名用有意义的名字(如users、products)
- 字段名用简单易懂的名字
-
数据组织建议
- 相关的数据尽量放在一起
- 避免过深的数据嵌套
- 数组中不要存太多数据
-
查询建议
- 常用查询字段要加索引
- 查询时只获取需要的字段
- 避免一次查询太多数据
-
实用技巧
- 使用复合查询减少查询次数
- 使用批量操作提高效率
- 定期备份重要数据
二、MongoDB简介
2.1 什么是MongoDB?
MongoDB是一个开源的文档型数据库,具有以下特点:
- 高性能、高可用性、易扩展
- 支持动态查询
- 支持索引
- 支持复制和分片
- 支持多种编程语言
2.2 基本概念
-
数据库(Database)
- MongoDB中的数据库是一个集合的容器
- 每个数据库都有独立的权限控制
-
集合(Collection)
- 类似于关系型数据库中的表
- 不需要预先定义结构
- 可以包含不同结构的文档
-
文档(Document)
- 类似于关系型数据库中的行
- 使用BSON格式(JSON的二进制形式)
- 可以包含不同类型的字段
-
字段(Field)
- 文档中的键值对
- 支持多种数据类型
- 可以嵌套和数组
三、MongoDB安装与配置
3.1 安装MongoDB
bash
# Windows安装
# 1. 下载MongoDB安装包
# 2. 运行安装程序
# 3. 配置环境变量
# Linux安装
sudo apt-get update
sudo apt-get install -y mongodb
# Mac安装
brew tap mongodb/brew
brew install mongodb-community
3.2 启动MongoDB
bash
# Windows启动
net start MongoDB
# Linux启动
sudo systemctl start mongodb
# Mac启动
brew services start mongodb-community
3.3 连接MongoDB
bash
# 命令行连接
mongosh
# 指定主机和端口连接
mongosh --host localhost --port 27017
# 使用用户名密码连接
mongosh --username admin --password password
四、MongoDB基本操作
4.1 数据库操作
javascript
// 创建/切换数据库
use mydb
// 查看所有数据库
show dbs
// 删除当前数据库
db.dropDatabase()
// 查看当前数据库
db
4.2 集合操作
javascript
// 创建集合
db.createCollection("users")
// 查看所有集合
show collections
// 删除集合
db.users.drop()
// 查看集合统计信息
db.users.stats()
4.3 文档操作
javascript
// 插入单个文档
db.users.insertOne({
name: "张三",
age: 25,
email: "[email protected]",
hobbies: ["读书", "运动"],
address: {
city: "北京",
street: "朝阳区"
}
})
// 插入多个文档
db.users.insertMany([
{
name: "李四",
age: 30,
email: "[email protected]"
},
{
name: "王五",
age: 28,
email: "[email protected]"
}
])
// 查询文档
db.users.find()
// 条件查询
db.users.find({ age: { $gt: 25 } })
// 更新文档
db.users.updateOne(
{ name: "张三" },
{ $set: { age: 26 } }
)
// 删除文档
db.users.deleteOne({ name: "张三" })
五、MongoDB查询操作
5.1 基础查询
javascript
// 查询所有文档
db.users.find()
// 条件查询
db.users.find({ age: 25 })
// 比较操作符
db.users.find({ age: { $gt: 25 } }) // 大于
db.users.find({ age: { $lt: 25 } }) // 小于
db.users.find({ age: { $gte: 25 } }) // 大于等于
db.users.find({ age: { $lte: 25 } }) // 小于等于
db.users.find({ age: { $ne: 25 } }) // 不等于
// 逻辑操作符
db.users.find({ $or: [{ age: 25 }, { age: 30 }] }) // OR
db.users.find({ $and: [{ age: 25 }, { name: "张三" }] }) // AND
db.users.find({ age: { $not: { $gt: 25 } } }) // NOT
// 限制返回字段
db.users.find({}, { name: 1, age: 1, _id: 0 })
// 排序
db.users.find().sort({ age: 1 }) // 升序
db.users.find().sort({ age: -1 }) // 降序
// 分页
db.users.find().skip(10).limit(5)
5.2 高级查询
javascript
// 正则表达式查询
db.users.find({ name: /^张/ })
// 数组查询
db.users.find({ hobbies: "读书" })
db.users.find({ hobbies: { $all: ["读书", "运动"] } })
db.users.find({ hobbies: { $size: 2 } })
// 嵌套文档查询
db.users.find({ "address.city": "北京" })
// 聚合查询
db.users.aggregate([
{ $group: { _id: "$age", count: { $sum: 1 } } },
{ $sort: { count: -1 } }
])
进阶篇
六、MongoDB索引
6.1 索引操作
javascript
// 创建索引
db.users.createIndex({ email: 1 })
// 创建唯一索引
db.users.createIndex({ email: 1 }, { unique: true })
// 创建复合索引
db.users.createIndex({ name: 1, age: -1 })
// 查看索引
db.users.getIndexes()
// 删除索引
db.users.dropIndex({ email: 1 })
6.2 索引类型
- 单字段索引
- 复合索引
- 多键索引
- 文本索引
- 地理空间索引
- 哈希索引
七、MongoDB聚合操作
7.1 聚合管道
javascript
// 基本聚合
db.users.aggregate([
{ $match: { age: { $gt: 25 } } },
{ $group: { _id: "$age", count: { $sum: 1 } } },
{ $sort: { count: -1 } }
])
// 复杂聚合
db.orders.aggregate([
{ $match: { status: "completed" } },
{ $group: {
_id: "$customer_id",
total: { $sum: "$amount" },
count: { $sum: 1 }
}},
{ $lookup: {
from: "customers",
localField: "_id",
foreignField: "_id",
as: "customer"
}},
{ $unwind: "$customer" },
{ $project: {
customer_name: "$customer.name",
total: 1,
count: 1
}}
])
7.2 聚合操作符
- $match:过滤文档
- $group:分组
- $sort:排序
- $limit:限制
- $skip:跳过
- $project:投影
- $lookup:关联查询
- $unwind:展开数组
八、MongoDB数据模型
8.1 文档模型
javascript
// 嵌入式文档
{
_id: ObjectId("..."),
name: "张三",
orders: [
{
order_id: "001",
amount: 100,
items: [
{ product: "手机", quantity: 1 },
{ product: "耳机", quantity: 2 }
]
}
]
}
// 引用式文档
{
_id: ObjectId("..."),
name: "张三",
order_ids: [
ObjectId("..."),
ObjectId("...")
]
}
8.2 数据关系
- 一对一关系
- 一对多关系
- 多对多关系
九、MongoDB安全
9.1 用户管理
javascript
// 创建用户
db.createUser({
user: "admin",
pwd: "password",
roles: ["userAdminAnyDatabase"]
})
// 修改用户
db.updateUser("admin", {
roles: ["userAdminAnyDatabase", "readWriteAnyDatabase"]
})
// 删除用户
db.dropUser("admin")
9.2 访问控制
javascript
// 启用认证
security:
authorization: enabled
// 设置访问权限
db.grantRolesToUser("user", ["readWrite"])
十、MongoDB备份恢复
10.1 备份操作
bash
# 备份整个数据库
mongodump --db mydb --out /backup
# 备份特定集合
mongodump --db mydb --collection users --out /backup
# 压缩备份
mongodump --db mydb --gzip --archive=/backup/backup.gz
10.2 恢复操作
bash
# 恢复整个数据库
mongorestore --db mydb /backup/mydb
# 恢复特定集合
mongorestore --db mydb --collection users /backup/mydb/users.bson
# 恢复压缩备份
mongorestore --gzip --archive=/backup/backup.gz
十一、MongoDB性能优化
11.1 查询优化
- 使用索引
- 限制返回字段
- 使用投影
- 使用分页
- 避免使用正则表达式
11.2 索引优化
- 创建合适的索引
- 避免过多索引
- 使用复合索引
- 定期维护索引
11.3 配置优化
yaml
# mongod.conf
storage:
wiredTiger:
engineConfig:
cacheSizeGB: 4
collectionConfig:
blockCompressor: snappy
operationProfiling:
mode: slowOp
slowOpThresholdMs: 100
replication:
oplogSizeMB: 10240
十二、MongoDB高级特性
12.1 Change Streams
javascript
// 监听集合变化
const changeStream = db.collection('users').watch();
changeStream.on('change', (change) => {
console.log('检测到变化:', change);
});
// 使用管道过滤器
const pipeline = [
{ $match: { 'operationType': 'insert' } }
];
const filteredStream = db.collection('users').watch(pipeline);
12.2 事务处理
javascript
// 开启事务
const session = db.getMongo().startSession();
session.startTransaction();
try {
// 转账操作示例
db.accounts.updateOne(
{ userId: "user1" },
{ $inc: { balance: -100 } },
{ session }
);
db.accounts.updateOne(
{ userId: "user2" },
{ $inc: { balance: 100 } },
{ session }
);
await session.commitTransaction();
} catch (error) {
await session.abortTransaction();
throw error;
} finally {
session.endSession();
}
12.3 GridFS文件存储
javascript
// 存储大文件
const bucket = new GridFSBucket(db);
fs.createReadStream('video.mp4')
.pipe(bucket.openUploadStream('video.mp4'));
// 读取文件
bucket.openDownloadStreamByName('video.mp4')
.pipe(fs.createWriteStream('downloaded-video.mp4'));
十三、MongoDB复制集
13.1 复制集配置
yaml
# mongod.conf
replication:
replSetName: "myReplicaSet"
javascript
// 初始化复制集
rs.initiate({
_id: "myReplicaSet",
members: [
{ _id: 0, host: "mongodb1:27017" },
{ _id: 1, host: "mongodb2:27017" },
{ _id: 2, host: "mongodb3:27017" }
]
});
// 查看复制集状态
rs.status();
// 添加节点
rs.add("mongodb4:27017");
// 移除节点
rs.remove("mongodb4:27017");
13.2 复制集运维
javascript
// 主节点降级
rs.stepDown();
// 设置优先级
cfg = rs.conf();
cfg.members[0].priority = 2;
rs.reconfig(cfg);
// 设置隐藏节点
cfg.members[2].hidden = true;
cfg.members[2].priority = 0;
rs.reconfig(cfg);
十四、MongoDB分片集群
14.1 分片集群架构
- Config Server(配置服务器)
- Shard Server(分片服务器)
- Mongos Router(路由服务器)
14.2 分片配置
javascript
// 启用分片
sh.enableSharding("mydb");
// 对集合进行分片
sh.shardCollection("mydb.users", { userId: "hashed" });
// 范围分片
sh.shardCollection("mydb.orders", { orderDate: 1 });
// 复合分片键
sh.shardCollection("mydb.products", { category: 1, price: 1 });
应用篇
十五、MongoDB性能诊断
15.1 查询分析
javascript
// 执行计划分析
db.users.find({ age: { $gt: 25 } }).explain("executionStats");
// 慢查询分析
db.setProfilingLevel(1, { slowms: 100 });
db.system.profile.find().sort({ ts: -1 });
// 查询统计
db.users.aggregate([
{ $indexStats: {} }
]);
15.2 性能监控
javascript
// 服务器状态
db.serverStatus();
// 数据库统计
db.stats();
// 集合统计
db.users.stats();
// 连接情况
db.currentOp();
十六、MongoDB数据迁移
16.1 数据导出
bash
# 导出JSON格式
mongoexport --db mydb --collection users --out users.json
# 导出CSV格式
mongoexport --db mydb --collection users --type=csv --fields name,age,email --out users.csv
# 条件导出
mongoexport --db mydb --collection users --query '{"age":{"$gt":25}}' --out users_filtered.json
16.2 数据导入
bash
# 导入JSON
mongoimport --db mydb --collection users --file users.json
# 导入CSV
mongoimport --db mydb --collection users --type csv --headerline --file users.csv
# 导入时进行转换
mongoimport --db mydb --collection users --file users.json --transform 'this.age = Number(this.age)'
十七、MongoDB应用开发最佳实践
17.1 数据建模
javascript
// 反范式设计示例
{
_id: ObjectId("..."),
orderId: "ORD001",
customer: {
name: "张三",
email: "[email protected]",
address: "北京市朝阳区"
},
items: [
{
productId: "P001",
name: "iPhone",
price: 6999,
quantity: 1
}
],
totalAmount: 6999,
status: "completed"
}
17.2 查询优化技巧
javascript
// 使用覆盖索引
db.users.find(
{ age: { $gt: 25 } },
{ _id: 0, name: 1, age: 1 }
).hint({ age: 1, name: 1 });
// 使用投影减少网络传输
db.users.find(
{ },
{ name: 1, age: 1, _id: 0 }
);
// 批量操作
db.users.bulkWrite([
{ insertOne: { document: { name: "张三", age: 25 } } },
{ updateOne: {
filter: { name: "李四" },
update: { $set: { age: 26 } }
} },
{ deleteOne: { filter: { name: "王五" } } }
]);
17.3 错误处理
javascript
try {
// 插入唯一索引冲突处理
await db.users.insertOne({
email: "[email protected]",
name: "张三"
});
} catch (error) {
if (error.code === 11000) {
console.log('邮箱已存在');
} else {
throw error;
}
}
十八、MongoDB运维管理
18.1 日志管理
yaml
# mongod.conf
systemLog:
destination: file
path: "/var/log/mongodb/mongod.log"
logAppend: true
logRotate: rename
18.2 监控告警
javascript
// 设置告警阈值
db.createCollection("alerts");
db.alerts.createIndex({ "timestamp": 1 }, { expireAfterSeconds: 86400 });
// 监控连接数
const connections = db.serverStatus().connections;
if (connections.current > connections.available * 0.8) {
db.alerts.insertOne({
type: "connection_warning",
message: "连接数超过80%",
timestamp: new Date()
});
}
18.3 容量规划
- 评估数据增长率
- 监控磁盘使用情况
- 规划扩容时机
- 制定备份策略
十九、MongoDB常见应用场景示例
19.1 用户管理系统
javascript
// 用户注册
db.users.insertOne({
用户名: "xiaoming",
密码: "123456", // 实际应用中要加密
注册时间: new Date(),
最后登录: new Date(),
状态: "正常"
})
// 用户登录验证
db.users.findOne({
用户名: "xiaoming",
密码: "123456"
})
// 更新登录时间
db.users.updateOne(
{用户名: "xiaoming"},
{$set: {最后登录: new Date()}}
)
19.2 商品评论系统
javascript
// 添加评论
db.comments.insertOne({
商品ID: "prod123",
用户名: "xiaoming",
评分: 5,
内容: "很好用!",
评论时间: new Date(),
点赞数: 0
})
// 查看商品评论
db.comments.find({商品ID: "prod123"})
// 给评论点赞
db.comments.updateOne(
{_id: "评论ID"},
{$inc: {点赞数: 1}} // $inc表示增加
)
19.3 内容管理系统
javascript
// 创建文章
db.articles.insertOne({
标题: "MongoDB入门指南",
作者: "xiaoming",
内容: "MongoDB是一个文档型数据库...",
标签: ["数据库", "NoSQL", "MongoDB"],
创建时间: new Date(),
更新时间: new Date(),
阅读量: 0,
点赞数: 0
})
// 更新文章
db.articles.updateOne(
{标题: "MongoDB入门指南"},
{
$set: {更新时间: new Date()},
$inc: {阅读量: 1}
}
)
// 按标签查询文章
db.articles.find({标签: "MongoDB"})
19.4 日志系统
javascript
// 记录系统日志
db.logs.insertOne({
级别: "ERROR",
模块: "用户认证",
消息: "用户登录失败",
详情: "密码错误",
时间: new Date(),
用户ID: "user123",
IP地址: "192.168.1.1"
})
// 查询错误日志
db.logs.find({级别: "ERROR"})
// 按时间范围查询
db.logs.find({
时间: {
$gte: new Date(new Date().setDate(new Date().getDate() - 7)),
$lte: new Date()
}
})
二十、MongoDB与Java集成
20.1 MongoDB Java驱动
java
// 添加MongoDB Java驱动依赖
// Maven
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-sync</artifactId>
<version>4.11.1</version>
</dependency>
// Gradle
implementation 'org.mongodb:mongodb-driver-sync:4.11.1'
20.2 连接MongoDB
java
// 创建MongoDB客户端
MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017");
// 获取数据库
MongoDatabase database = mongoClient.getDatabase("mydb");
// 获取集合
MongoCollection<Document> collection = database.getCollection("users");
// 关闭连接
mongoClient.close();
20.3 基本操作示例
java
// 插入文档
Document document = new Document("name", "张三")
.append("age", 25)
.append("email", "[email protected]");
collection.insertOne(document);
// 查询文档
Document query = new Document("name", "张三");
Document result = collection.find(query).first();
System.out.println(result.toJson());
// 更新文档
Document updateQuery = new Document("name", "张三");
Document update = new Document("$set", new Document("age", 26));
collection.updateOne(updateQuery, update);
// 删除文档
Document deleteQuery = new Document("name", "张三");
collection.deleteOne(deleteQuery);
20.4 使用MongoDB Java驱动的高级功能
java
// 批量操作
List<WriteModel<Document>> writes = new ArrayList<>();
writes.add(new InsertOneModel<>(new Document("name", "李四").append("age", 30)));
writes.add(new UpdateOneModel<>(
new Document("name", "王五"),
new Document("$set", new Document("age", 28))
));
writes.add(new DeleteOneModel<>(new Document("name", "赵六")));
BulkWriteResult bulkWriteResult = collection.bulkWrite(writes);
System.out.println("插入: " + bulkWriteResult.getInsertedCount());
System.out.println("更新: " + bulkWriteResult.getModifiedCount());
System.out.println("删除: " + bulkWriteResult.getDeletedCount());
// 聚合操作
List<Document> pipeline = Arrays.asList(
new Document("$match", new Document("age", new Document("$gt", 25))),
new Document("$group", new Document("_id", "$age")
.append("count", new Document("$sum", 1))),
new Document("$sort", new Document("count", -1))
);
MongoCursor<Document> cursor = collection.aggregate(pipeline).iterator();
while (cursor.hasNext()) {
System.out.println(cursor.next().toJson());
}
二十一、MongoDB与Spring Boot集成
21.1 添加Spring Data MongoDB依赖
xml
<!-- Maven -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<!-- Gradle -->
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'
21.2 配置MongoDB连接
yaml
# application.yml
spring:
data:
mongodb:
uri: mongodb://localhost:27017/mydb
# 或者使用以下配置
# host: localhost
# port: 27017
# database: mydb
# username: admin
# password: password
21.3 创建实体类
java
@Document(collection = "users")
public class User {
@Id
private String id;
private String name;
private int age;
private String email;
private List<String> hobbies;
private Address address;
// 构造函数、getter和setter方法
// 内部类
public static class Address {
private String city;
private String street;
// 构造函数、getter和setter方法
}
}
21.4 创建Repository接口
java
@Repository
public interface UserRepository extends MongoRepository<User, String> {
// 自定义查询方法
List<User> findByAgeGreaterThan(int age);
List<User> findByNameStartingWith(String prefix);
Optional<User> findByEmail(String email);
// 使用@Query注解自定义查询
@Query("{ 'age' : { $gt : ?0, $lt : ?1 } }")
List<User> findByAgeBetween(int minAge, int maxAge);
}
21.5 使用MongoDB Template
java
@Service
public class UserService {
@Autowired
private MongoTemplate mongoTemplate;
public List<User> findUsersByAge(int age) {
Query query = new Query(Criteria.where("age").gt(age));
return mongoTemplate.find(query, User.class);
}
public void updateUserAge(String id, int newAge) {
Query query = new Query(Criteria.where("id").is(id));
Update update = new Update().set("age", newAge);
mongoTemplate.updateFirst(query, update, User.class);
}
public List<User> aggregateUsersByAge() {
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.match(Criteria.where("age").gt(25)),
Aggregation.group("age").count().as("count"),
Aggregation.sort(Sort.Direction.DESC, "count")
);
AggregationResults<User> results = mongoTemplate.aggregate(
aggregation, "users", User.class);
return results.getMappedResults();
}
}
二十二、MongoDB与Docker部署
22.1 使用Docker运行MongoDB
bash
# 拉取MongoDB镜像
docker pull mongo:latest
# 运行MongoDB容器
docker run -d --name mongodb -p 27017:27017 mongo:latest
# 运行MongoDB容器(带数据持久化)
docker run -d --name mongodb -p 27017:27017 -v /data/mongodb:/data/db mongo:latest
# 运行MongoDB容器(带认证)
docker run -d --name mongodb -p 27017:27017 -e MONGO_INITDB_ROOT_USERNAME=admin -e MONGO_INITDB_ROOT_PASSWORD=password mongo:latest
22.2 使用Docker Compose部署MongoDB
yaml
# docker-compose.yml
version: '3'
services:
mongodb:
image: mongo:latest
container_name: mongodb
ports:
- "27017:27017"
volumes:
- ./data:/data/db
environment:
- MONGO_INITDB_ROOT_USERNAME=admin
- MONGO_INITDB_ROOT_PASSWORD=password
networks:
- mongo-network
mongo-express:
image: mongo-express:latest
container_name: mongo-express
ports:
- "8081:8081"
environment:
- ME_CONFIG_MONGODB_ADMINUSERNAME=admin
- ME_CONFIG_MONGODB_ADMINPASSWORD=password
- ME_CONFIG_MONGODB_URL=mongodb://admin:password@mongodb:27017/
depends_on:
- mongodb
networks:
- mongo-network
networks:
mongo-network:
driver: bridge
22.3 使用Docker部署MongoDB复制集
yaml
# docker-compose-replica.yml
version: '3'
services:
mongodb1:
image: mongo:latest
container_name: mongodb1
command: mongod --replSet rs0 --bind_ip_all
ports:
- "27017:27017"
volumes:
- ./data1:/data/db
networks:
- mongo-network
mongodb2:
image: mongo:latest
container_name: mongodb2
command: mongod --replSet rs0 --bind_ip_all
ports:
- "27018:27017"
volumes:
- ./data2:/data/db
networks:
- mongo-network
mongodb3:
image: mongo:latest
container_name: mongodb3
command: mongod --replSet rs0 --bind_ip_all
ports:
- "27019:27017"
volumes:
- ./data3:/data/db
networks:
- mongo-network
networks:
mongo-network:
driver: bridge
bash
# 初始化复制集
docker exec -it mongodb1 mongosh --eval "rs.initiate({
_id: 'rs0',
members: [
{_id: 0, host: 'mongodb1:27017'},
{_id: 1, host: 'mongodb2:27017'},
{_id: 2, host: 'mongodb3:27017'}
]
})"
最佳实践篇
二十三、MongoDB常见问题解答
23.1 连接问题
问题 : 无法连接到MongoDB服务器
解决方案:
- 检查MongoDB服务是否正在运行
- 检查防火墙设置,确保端口27017开放
- 检查MongoDB配置文件中的bindIp设置
- 如果使用认证,确保用户名和密码正确
23.2 性能问题
问题 : MongoDB查询速度慢
解决方案:
- 为常用查询字段创建索引
- 使用explain()分析查询执行计划
- 优化查询,只返回需要的字段
- 检查服务器资源使用情况(CPU、内存、磁盘I/O)
- 考虑增加服务器资源或使用分片集群
23.3 数据一致性问题
问题 : 在复制集中出现数据不一致
解决方案:
- 检查复制集状态:
rs.status()
- 检查主节点和从节点的数据差异
- 如果从节点落后太多,考虑重新同步
- 确保网络连接稳定,避免网络分区
23.4 内存问题
问题 : MongoDB占用过多内存
解决方案:
- 调整WiredTiger缓存大小
- 监控内存使用情况
- 考虑增加服务器内存
- 优化查询和索引,减少内存使用
23.5 磁盘空间问题
问题 : MongoDB磁盘空间不足
解决方案:
- 清理不需要的数据
- 压缩集合:
db.runCommand({compact: "collection_name"})
- 增加磁盘空间
- 考虑使用分片集群分散数据
二十四、MongoDB最佳实践总结
24.1 数据建模最佳实践
-
嵌入vs引用
- 一对少关系:使用嵌入
- 一对多关系:根据查询模式决定
- 多对多关系:通常使用引用
-
文档大小
- 保持文档大小在16MB以下
- 避免过深的嵌套(不超过3-4层)
- 避免过大的数组
-
字段命名
- 使用简短但有意义的字段名
- 保持命名风格一致
- 避免使用特殊字符
24.2 查询优化最佳实践
-
索引策略
- 为所有查询创建适当的索引
- 避免过多索引(每个集合不超过64个)
- 使用复合索引支持多字段查询
- 考虑索引顺序(等值查询字段放在前面)
-
查询模式
- 使用覆盖索引减少内存使用
- 使用投影只返回需要的字段
- 使用批量操作代替多次单文档操作
- 避免使用正则表达式进行前缀查询
24.3 运维最佳实践
-
监控
- 监控服务器资源使用情况
- 监控查询性能
- 监控复制集状态
- 设置告警阈值
-
备份
- 定期备份数据
- 测试恢复流程
- 保存备份记录
- 考虑使用云服务提供商的备份功能
-
安全
- 启用认证
- 限制网络访问
- 定期更新密码
- 使用TLS/SSL加密传输
-
扩展
- 垂直扩展:增加服务器资源
- 水平扩展:使用分片集群
- 根据数据增长和访问模式规划扩展策略
24.4 应用开发最佳实践
-
连接管理
- 使用连接池
- 正确关闭连接
- 处理连接异常
-
错误处理
- 捕获并处理MongoDB异常
- 实现重试机制
- 记录错误日志
-
事务使用
- 只在必要时使用事务
- 保持事务简短
- 考虑使用补偿事务代替长时间运行的事务
-
代码组织
- 使用数据访问层封装MongoDB操作
- 使用ORM框架简化开发
- 遵循领域驱动设计原则