MongoDB 中文教程
1. 核心概念
MongoDB 是一个开源的文档数据库,属于 NoSQL 数据库的一种。它使用 BSON(Binary JSON)格式存储数据,提供了灵活的数据模型和强大的查询能力。
1.1 主要特点
- 文档模型:使用类似 JSON 的文档存储数据,结构灵活
- 无模式:不需要预定义表结构,支持动态添加字段
- 查询能力:支持丰富的查询操作,包括范围查询、正则表达式、聚合等
- 索引支持:支持多种类型的索引,提高查询性能
- 复制集:提供高可用性和数据冗余
- 分片:支持水平扩展,处理大规模数据
- 聚合框架:支持复杂的数据聚合操作
- 地理空间查询:支持地理位置数据和查询
1.2 技术栈特点
- 文档存储:使用 BSON 格式存储数据,结构灵活
- 分布式架构:支持复制集和分片,提供高可用性和扩展性
- 高性能:内存映射存储引擎,提供快速的读写操作
- 可扩展性:支持水平扩展,处理大规模数据
- 丰富的查询功能:支持复杂的查询操作和聚合
2. 安装配置
2.1 安装
2.1.1 Windows 安装
- 从 MongoDB 官方网站 下载 Windows 版本的 MongoDB
- 运行安装程序,按照向导完成安装
- 配置环境变量,将 MongoDB 的 bin 目录添加到 PATH 中
- 创建数据目录和日志目录:
mkdir -p C:\data\db mkdir -p C:\data\log - 启动 MongoDB 服务:
mongod --dbpath=C:\data\db --logpath=C:\data\log\mongod.log --logappend
2.1.2 Linux 安装
使用包管理器安装:
# Ubuntu/Debian
wget -qO - https://www.mongodb.org/static/pgp/server-6.0.asc | sudo apt-key add -
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/6.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-6.0.list
sudo apt-get update
sudo apt-get install -y mongodb-org
# 启动服务
sudo systemctl start mongod
# 设置开机自启
sudo systemctl enable mongod
# CentOS/RHEL
sudo tee /etc/yum.repos.d/mongodb-org-6.0.repo << 'EOF'
[mongodb-org-6.0]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/6.0/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-6.0.asc
EOF
sudo yum install -y mongodb-org
# 启动服务
sudo systemctl start mongod
# 设置开机自启
sudo systemctl enable mongod2.1.3 macOS 安装
使用 Homebrew 安装:
brew tap mongodb/brew
brew install mongodb-community
# 启动服务
brew services start mongodb-community2.2 基本配置
MongoDB 的配置文件通常位于 /etc/mongod.conf(Linux)或 MongoDB 安装目录下的 mongod.conf(Windows/macOS)。
主要配置项:
# 存储配置
storage:
dbPath: /var/lib/mongodb
journal:
enabled: true
# 网络配置
net:
port: 27017
bindIp: 127.0.0.1
# 复制集配置
replication:
replSetName: "rs0"
# 分片配置
sharding:
clusterRole: "shardsvr"
# 安全配置
security:
authorization: "enabled"2.3 启动 MongoDB
2.3.1 启动服务器
# 使用默认配置启动
mongod
# 使用指定配置文件启动
mongod --config /etc/mongod.conf
# 以守护进程方式启动
mongod --fork --logpath /var/log/mongodb/mongod.log2.3.2 启动客户端
# 基本连接
mongo
# 指定主机和端口
mongo --host host --port port
# 连接到指定数据库
mongo database
# 使用用户名和密码连接
mongo -u username -p password --authenticationDatabase admin3. 基本使用
3.1 数据库操作
# 查看当前数据库
db
# 切换数据库(如果不存在则创建)
use database_name
# 查看所有数据库
show dbs
# 删除当前数据库
db.dropDatabase()3.2 集合操作
# 创建集合
db.createCollection("collection_name")
# 查看集合
show collections
# 删除集合
db.collection_name.drop()
# 重命名集合
db.collection_name.renameCollection("new_collection_name")3.3 文档操作
3.3.1 插入文档
# 插入单个文档
db.collection_name.insertOne({
name: "张三",
age: 30,
email: "zhangsan@example.com"
})
# 插入多个文档
db.collection_name.insertMany([
{
name: "张三",
age: 30,
email: "zhangsan@example.com"
},
{
name: "李四",
age: 25,
email: "lisi@example.com"
}
])
# 旧版插入方法(兼容)
db.collection_name.insert({
name: "张三",
age: 30,
email: "zhangsan@example.com"
})3.3.2 查询文档
# 查询所有文档
db.collection_name.find()
# 格式化查询结果
db.collection_name.find().pretty()
# 按条件查询
db.collection_name.find({ age: 30 })
# 条件操作符查询
db.collection_name.find({ age: { $gt: 25 } }) # 大于 25
db.collection_name.find({ age: { $gte: 25 } }) # 大于等于 25
db.collection_name.find({ age: { $lt: 35 } }) # 小于 35
db.collection_name.find({ age: { $lte: 35 } }) # 小于等于 35
db.collection_name.find({ age: { $ne: 30 } }) # 不等于 30
db.collection_name.find({ age: { $in: [25, 30, 35] } }) # 在数组中
db.collection_name.find({ age: { $nin: [25, 30, 35] } }) # 不在数组中
# 逻辑操作符查询
db.collection_name.find({ $and: [{ age: { $gt: 25 } }, { age: { $lt: 35 } }] }) # 与
db.collection_name.find({ $or: [{ age: { $lt: 25 } }, { age: { $gt: 35 } }] }) # 或
db.collection_name.find({ $not: { age: { $eq: 30 } } }) # 非
# 字段操作符查询
db.collection_name.find({ name: { $exists: true } }) # 字段存在
db.collection_name.find({ name: { $type: "string" } }) # 字段类型
# 正则表达式查询
db.collection_name.find({ name: /^张/ }) # 以张开头
db.collection_name.find({ name: /三$/ }) # 以三结尾
db.collection_name.find({ name: /李/ }) # 包含李
# 限制和跳过
db.collection_name.find().limit(10) # 限制返回 10 条
db.collection_name.find().skip(5) # 跳过前 5 条
db.collection_name.find().skip(5).limit(10) # 跳过前 5 条,返回 10 条
# 排序
db.collection_name.find().sort({ age: 1 }) # 升序
db.collection_name.find().sort({ age: -1 }) # 降序
# 投影(只返回指定字段)
db.collection_name.find({}, { name: 1, age: 1 }) # 返回 name 和 age 字段
db.collection_name.find({}, { _id: 0, name: 1 }) # 不返回 _id 字段,返回 name 字段3.3.3 更新文档
# 更新单个文档
db.collection_name.updateOne(
{ name: "张三" },
{
$set: { age: 31, email: "zhangsanupdated@example.com" },
$currentDate: { lastModified: true }
}
)
# 更新多个文档
db.collection_name.updateMany(
{ age: { $lt: 30 } },
{
$set: { status: "young" }
}
)
# 替换文档
db.collection_name.replaceOne(
{ name: "张三" },
{
name: "张三",
age: 32,
email: "zhangsan@example.com",
address: "北京市"
}
)
# 旧版更新方法(兼容)
db.collection_name.update(
{ name: "张三" },
{
$set: { age: 31 }
}
)
# 更新操作符
# $set: 设置字段值
# $unset: 删除字段
# $inc: 增加字段值
# $mul: 乘以字段值
# $rename: 重命名字段
# $min: 仅当新值小于当前值时设置
# $max: 仅当新值大于当前值时设置
# $currentDate: 设置为当前日期3.3.4 删除文档
# 删除单个文档
db.collection_name.deleteOne({ name: "张三" })
# 删除多个文档
db.collection_name.deleteMany({ age: { $lt: 25 } })
# 旧版删除方法(兼容)
db.collection_name.remove({ name: "张三" })
db.collection_name.remove({ age: { $lt: 25 } }, { justOne: true }) # 仅删除一个
# 删除所有文档(保留集合)
db.collection_name.deleteMany({})3.4 索引操作
# 创建单字段索引
db.collection_name.createIndex({ age: 1 }) # 升序
db.collection_name.createIndex({ age: -1 }) # 降序
# 创建复合索引
db.collection_name.createIndex({ name: 1, age: -1 })
# 创建唯一索引
db.collection_name.createIndex({ email: 1 }, { unique: true })
# 创建文本索引
db.collection_name.createIndex({ content: "text" })
# 创建地理空间索引
db.collection_name.createIndex({ location: "2dsphere" })
# 查看索引
db.collection_name.getIndexes()
# 删除索引
db.collection_name.dropIndex("index_name")
db.collection_name.dropIndex({ age: 1 }) # 通过字段删除
# 删除所有索引(保留 _id 索引)
db.collection_name.dropIndexes()4. 高级功能
4.1 聚合框架
聚合框架用于处理数据聚合操作,如分组、计数、求和等。
# 基本聚合
db.collection_name.aggregate([
{ $match: { age: { $gt: 25 } } }, # 过滤条件
{ $group: { _id: "$age", count: { $sum: 1 } } }, # 按年龄分组,计算数量
{ $sort: { count: -1 } } # 按数量降序排序
])
# 常用聚合操作符
# $match: 过滤文档
# $group: 分组文档
# $sort: 排序文档
# $limit: 限制文档数量
# $skip: 跳过文档
# $project: 投影字段
# $unwind: 展开数组字段
# $lookup: 关联查询(类似 SQL JOIN)
# $addFields: 添加新字段
# $out: 将结果输出到新集合
# 示例:计算每个年龄段的平均年龄和人数
db.collection_name.aggregate([
{ $group: {
_id: { $floor: { $divide: ["$age", 10] } }, # 按年龄分组(每 10 岁一组)
averageAge: { $avg: "$age" }, # 计算平均年龄
count: { $sum: 1 } # 计算人数
}
},
{ $sort: { _id: 1 } } # 按年龄段升序排序
])
# 示例:关联查询
db.orders.aggregate([
{
$lookup: {
from: "customers",
localField: "customerId",
foreignField: "_id",
as: "customer"
}
}
])4.2 复制集
复制集提供高可用性和数据冗余,由一个主节点和多个从节点组成。
4.2.1 配置复制集
- 启动多个 MongoDB 实例:
# 实例 1(主节点)
mongod --port 27017 --dbpath /data/db1 --replSet rs0
# 实例 2(从节点)
mongod --port 27018 --dbpath /data/db2 --replSet rs0
# 实例 3(从节点)
mongod --port 27019 --dbpath /data/db3 --replSet rs0- 初始化复制集:
mongo --port 27017
rs.initiate({
_id: "rs0",
members: [
{ _id: 0, host: "localhost:27017" },
{ _id: 1, host: "localhost:27018" },
{ _id: 2, host: "localhost:27019" }
]
})4.2.2 管理复制集
# 查看复制集状态
rs.status()
# 查看复制集配置
rs.conf()
# 添加节点
rs.add("localhost:27020")
# 移除节点
rs.remove("localhost:27020")
# 手动故障转移
rs.stepDown()
# 强制重新配置
rs.reconfig(config, { force: true })4.3 分片
分片用于水平扩展,将数据分布到多个服务器上。
4.3.1 配置分片
- 启动配置服务器:
mongod --configsvr --replSet configrs --port 27019 --dbpath /data/configdb- 启动分片服务器:
mongod --shardsvr --replSet shard1rs --port 27017 --dbpath /data/shard1
mongod --shardsvr --replSet shard2rs --port 27018 --dbpath /data/shard2- 启动 mongos 路由器:
mongos --configdb configrs/localhost:27019 --port 27020- 配置分片:
mongo --port 27020
# 添加分片
sh.addShard("shard1rs/localhost:27017")
sh.addShard("shard2rs/localhost:27018")
# 启用数据库分片
sh.enableSharding("database_name")
# 配置集合分片键
sh.shardCollection("database_name.collection_name", { "_id": "hashed" })
sh.shardCollection("database_name.collection_name", { "age": 1 })4.4 地理空间查询
MongoDB 支持地理位置数据和查询。
# 插入地理空间数据
db.places.insertMany([
{
name: "北京",
location: {
type: "Point",
coordinates: [116.4074, 39.9042]
}
},
{
name: "上海",
location: {
type: "Point",
coordinates: [121.4737, 31.2304]
}
}
])
# 创建地理空间索引
db.places.createIndex({ location: "2dsphere" })
# 查询附近的位置
db.places.find({
location: {
$near: {
$geometry: {
type: "Point",
coordinates: [116.4074, 39.9042]
},
$maxDistance: 100000 # 100 公里
}
}
})
# 查询指定区域内的位置
db.places.find({
location: {
$geoWithin: {
$geometry: {
type: "Polygon",
coordinates: [
[
[116.0, 39.5],
[117.0, 39.5],
[117.0, 40.0],
[116.0, 40.0],
[116.0, 39.5]
]
]
}
}
}
})4.5 事务
MongoDB 4.0+ 支持多文档事务。
// 开始事务
session = db.getMongo().startSession()
transactionOptions = {
readPreference: "primary",
readConcern: { level: "local" },
writeConcern: { w: "majority" }
}
session.startTransaction(transactionOptions)
try {
// 操作 1
db = session.getDatabase("test")
db.accounts.updateOne({ _id: 1 }, { $inc: { balance: -100 } })
// 操作 2
db.accounts.updateOne({ _id: 2 }, { $inc: { balance: 100 } })
// 提交事务
session.commitTransaction()
print("事务提交成功")
} catch (error) {
print("事务失败:", error)
session.abortTransaction()
} finally {
session.endSession()
}5. 最佳实践
5.1 数据模型设计
- 文档结构:根据应用访问模式设计文档结构,避免过度嵌套
- 字段命名:使用有意义的字段名,避免使用保留字
- 数据类型:选择合适的数据类型,提高存储效率
- 引用 vs 嵌入:根据数据访问模式选择合适的关系表示方式
- 嵌入:适合一对一或一对多关系,数据访问频繁
- 引用:适合多对多关系,数据大小较大
5.2 性能优化
5.2.1 索引优化
- 创建合适的索引:根据查询模式创建索引
- 复合索引:使用复合索引覆盖多个查询条件
- 索引顺序:将选择性高的字段放在索引前面
- 避免过度索引:过多的索引会影响写入性能
- 定期重建索引:对于频繁更新的集合,定期重建索引
5.2.2 查询优化
- 使用投影:只返回需要的字段
- 避免全表扫描:使用索引覆盖查询
- 限制结果集大小:使用 limit() 限制返回的文档数量
- 避免使用 $where:$where 操作符会降低查询性能
- 使用聚合框架:对于复杂查询,使用聚合框架而非多个查询
5.2.3 写入优化
- 批量操作:使用 insertMany() 批量插入文档
- 有序 vs 无序:对于不需要顺序的批量操作,使用 ordered: false
- 批量更新:使用 updateMany() 批量更新文档
- 避免频繁更新:减少小的、频繁的更新操作
- 使用 upsert:对于可能存在的文档,使用 upsert 避免额外的查询
5.3 安全性
5.3.1 访问控制
- 启用认证:在生产环境中启用 MongoDB 认证
- 创建用户:为不同的应用创建不同的用户,分配适当的权限
- 使用角色:使用内置角色或自定义角色管理权限
- 最小权限原则:只授予应用所需的最小权限
5.3.2 数据安全
- 加密:使用 WiredTiger 存储引擎的加密功能
- 备份:定期备份数据库
- 复制集:使用复制集提供数据冗余
- 防火墙:限制 MongoDB 端口的访问
- 网络加密:使用 TLS/SSL 加密网络通信
5.4 监控和维护
5.4.1 监控
- MongoDB Compass:使用官方 GUI 工具监控数据库
- mongostat:实时监控数据库状态
- mongotop:监控集合级别的操作时间
- **db.serverStatus()**:查看服务器状态
- **db.stats()**:查看数据库统计信息
- **db.collection.stats()**:查看集合统计信息
5.4.2 维护
- 定期备份:使用 mongodump 定期备份数据库
- 索引重建:定期重建索引,提高查询性能
- 碎片整理:对于 WiredTiger 存储引擎,定期运行 compact 命令
- 日志轮换:配置适当的日志轮换策略
- 监控磁盘空间:确保有足够的磁盘空间
6. 实际应用
6.1 Node.js 应用集成
使用 MongoDB Node.js 驱动程序集成 MongoDB。
6.1.1 安装驱动
npm install mongodb6.1.2 基本使用
const { MongoClient } = require('mongodb');
// 连接字符串
const uri = 'mongodb://localhost:27017';
const client = new MongoClient(uri);
async function run() {
try {
// 连接到 MongoDB
await client.connect();
console.log('已连接到 MongoDB');
// 选择数据库和集合
const database = client.db('test');
const collection = database.collection('users');
// 插入文档
const insertResult = await collection.insertOne({
name: '张三',
age: 30,
email: 'zhangsan@example.com'
});
console.log('插入结果:', insertResult);
// 查询文档
const findResult = await collection.find({ age: { $gt: 25 } }).toArray();
console.log('查询结果:', findResult);
// 更新文档
const updateResult = await collection.updateOne(
{ name: '张三' },
{ $set: { age: 31 } }
);
console.log('更新结果:', updateResult);
// 删除文档
const deleteResult = await collection.deleteOne({ name: '张三' });
console.log('删除结果:', deleteResult);
} finally {
// 关闭连接
await client.close();
console.log('已关闭 MongoDB 连接');
}
}
run().catch(console.dir);6.2 Express.js 应用集成
使用 Mongoose ODM 集成 MongoDB。
6.2.1 安装依赖
npm install express mongoose6.2.2 基本使用
const express = require('express');
const mongoose = require('mongoose');
const app = express();
const port = 3000;
// 连接 MongoDB
mongoose.connect('mongodb://localhost:27017/test', {
useNewUrlParser: true,
useUnifiedTopology: true
});
// 定义模型
const User = mongoose.model('User', {
name: String,
age: Number,
email: String
});
// 中间件
app.use(express.json());
// 路由
app.get('/users', async (req, res) => {
try {
const users = await User.find();
res.json(users);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.post('/users', async (req, res) => {
try {
const user = new User(req.body);
await user.save();
res.status(201).json(user);
} catch (error) {
res.status(400).json({ error: error.message });
}
});
app.get('/users/:id', async (req, res) => {
try {
const user = await User.findById(req.params.id);
if (!user) {
return res.status(404).json({ message: '用户不存在' });
}
res.json(user);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.put('/users/:id', async (req, res) => {
try {
const user = await User.findByIdAndUpdate(req.params.id, req.body, { new: true });
if (!user) {
return res.status(404).json({ message: '用户不存在' });
}
res.json(user);
} catch (error) {
res.status(400).json({ error: error.message });
}
});
app.delete('/users/:id', async (req, res) => {
try {
const user = await User.findByIdAndDelete(req.params.id);
if (!user) {
return res.status(404).json({ message: '用户不存在' });
}
res.json({ message: '用户已删除' });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// 启动服务器
app.listen(port, () => {
console.log(`服务器运行在 http://localhost:${port}`);
});6.3 数据备份和恢复
6.3.1 备份数据
使用 mongodump 工具备份数据:
# 备份所有数据库
mongodump
# 备份指定数据库
mongodump --db database_name
# 备份指定集合
mongodump --db database_name --collection collection_name
# 备份到指定目录
mongodump --out /backup/directory
# 使用用户名和密码备份
mongodump -u username -p password --authenticationDatabase admin6.3.2 恢复数据
使用 mongorestore 工具恢复数据:
# 恢复所有数据库
mongorestore
# 恢复指定数据库
mongorestore --db database_name /backup/directory/database_name
# 恢复指定集合
mongorestore --db database_name --collection collection_name /backup/directory/database_name/collection_name.bson
# 使用用户名和密码恢复
mongorestore -u username -p password --authenticationDatabase admin6.4 监控工具
6.4.1 MongoDB Compass
MongoDB Compass 是官方的 GUI 工具,提供可视化的数据库管理和监控功能。
6.4.2 mongostat
mongostat 提供实时的数据库状态监控:
# 基本监控
mongostat
# 监控指定主机和端口
mongostat --host host --port port
# 监控间隔
mongostat 10 # 每 10 秒监控一次6.4.3 mongotop
mongotop 提供集合级别的操作时间监控:
# 基本监控
mongotop
# 监控间隔
mongotop 10 # 每 10 秒监控一次7. 总结
MongoDB 是一个功能强大的文档数据库,具有灵活的数据模型、丰富的查询功能和良好的可扩展性。本文介绍了 MongoDB 的核心概念、安装配置、基本使用、高级功能、最佳实践和实际应用示例,希望能够帮助开发者更好地理解和使用 MongoDB。
7.1 主要优势
- 灵活的文档模型:使用类似 JSON 的文档存储数据,结构灵活
- 强大的查询能力:支持丰富的查询操作和聚合
- 高可用性:通过复制集提供高可用性和数据冗余
- 可扩展性:通过分片支持水平扩展
- 丰富的生态系统:提供多种语言的驱动程序和工具
- 地理空间支持:支持地理位置数据和查询
- 事务支持:支持多文档事务
7.2 适用场景
- 内容管理系统:灵活的文档模型适合存储各种类型的内容
- 实时分析:支持复杂的聚合操作和实时查询
- 移动应用后端:灵活的数据模型适合快速迭代的移动应用
- 物联网:支持存储和查询设备数据
- 社交网络:适合存储用户关系和社交数据
- 电子商务:支持存储产品信息和订单数据
- 游戏:适合存储游戏状态和用户数据
7.3 未来展望
MongoDB 作为一个成熟的开源项目,不断发展和完善。未来的 MongoDB 可能会:
- 进一步提高性能:优化存储引擎和查询执行
- 增强安全性:提供更多的安全特性和合规性支持
- 改进分片功能:提供更简单的分片管理和更灵活的分片策略
- 增强云集成:提供更好的云服务集成和管理工具
- 支持更多的数据类型:添加对新数据类型的支持
通过本文的学习,相信开发者已经对 MongoDB 有了全面的了解,可以开始在实际项目中使用 MongoDB 构建高性能、可扩展的应用了。