MongoDB数据库管理基础
一、MongoDB 基础概念
MongoDB 是一个基于分布式文件存储的开源数据库系统,由 C++ 语言编写。它旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。
1.1 数据模型
MongoDB 使用一种称为 BSON(Binary JSON)的二进制序列化格式来表示数据。BSON 类似于 JSON,但支持更多的数据类型,并且在空间和时间效率上更高。在 MongoDB 中,数据以文档(document)的形式存储,文档是一个键值对(key - value pairs)的集合。例如,一个简单的用户文档可以如下表示:
{
"name": "John Doe",
"age": 30,
"email": "johndoe@example.com",
"address": {
"street": "123 Main St",
"city": "Anytown",
"state": "CA",
"zip": "12345"
}
}
文档可以嵌套和包含数组,这使得 MongoDB 能够轻松处理复杂的数据结构。例如,一个包含多个爱好的用户文档:
{
"name": "Jane Smith",
"hobbies": ["reading", "swimming", "painting"]
}
1.2 集合(Collection)
集合是一组文档的容器。它类似于关系型数据库中的表,但集合没有固定的模式(schema)。这意味着集合中的文档可以具有不同的结构。例如,一个名为 users
的集合可以同时包含具有不同字段的用户文档:
// 第一个用户文档
{
"name": "Alice",
"age": 25
}
// 第二个用户文档
{
"name": "Bob",
"email": "bob@example.com",
"phone": "123 - 456 - 7890"
}
这种灵活性使得 MongoDB 在处理不断变化的数据结构时非常方便,尤其适合于敏捷开发和快速迭代的项目。
1.3 数据库(Database)
MongoDB 可以包含多个数据库,每个数据库都有自己的一组集合。数据库用于隔离不同的应用程序数据或不同的业务模块数据。例如,一个电子商务应用可能有一个数据库用于存储用户数据,另一个数据库用于存储产品数据。在 MongoDB 中,数据库名称是区分大小写的,并且有一些命名限制,例如不能包含空字符、点(.)等特殊字符。
二、MongoDB 安装与启动
2.1 安装 MongoDB
- Windows 系统:
- 从 MongoDB 官方网站(https://www.mongodb.com/try/download/community)下载适合 Windows 系统的安装包。
- 运行安装包,按照安装向导提示进行安装。在安装过程中,可以选择自定义安装路径等选项。默认情况下,MongoDB 会安装到
C:\Program Files\MongoDB\Server\版本号\
目录下。 - 安装完成后,需要创建数据目录。默认情况下,MongoDB 使用
C:\data\db
作为数据存储目录。如果该目录不存在,需要手动创建。
- Linux 系统(以 Ubuntu 为例):
- 导入 MongoDB 的 GPG 密钥:
wget -qO - https://www.mongodb.org/static/pgp/server - 6.0.asc | sudo apt - key add -
2. 创建 MongoDB 的软件源列表文件:
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
3. 更新软件包列表并安装 MongoDB:
sudo apt update
sudo apt install - y mongodb - org
- MacOS 系统:
- 可以使用 Homebrew 进行安装。首先确保已经安装了 Homebrew,如果没有安装,可以运行以下命令安装:
/bin/bash - c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
2. 安装 MongoDB:
brew install mongodb - community
2.2 启动 MongoDB
- Windows 系统:打开命令提示符,切换到 MongoDB 的
bin
目录(例如C:\Program Files\MongoDB\Server\版本号\bin
),然后运行以下命令启动 MongoDB 服务:
mongod
如果希望将 MongoDB 作为系统服务运行,可以使用以下命令安装服务:
mongod --config "C:\Program Files\MongoDB\Server\版本号\bin\mongod.cfg" --install
然后使用 net start MongoDB
命令启动服务。
- Linux 系统:在 Ubuntu 上,安装完成后 MongoDB 会自动作为服务启动。可以使用以下命令管理服务:
# 启动 MongoDB 服务
sudo systemctl start mongod
# 停止 MongoDB 服务
sudo systemctl stop mongod
# 重启 MongoDB 服务
sudo systemctl restart mongod
- MacOS 系统:使用 Homebrew 安装后,可以使用以下命令启动 MongoDB:
brew services start mongodb - community
要停止服务,可以使用:
brew services stop mongodb - community
三、MongoDB 基本操作
3.1 连接到 MongoDB
可以使用 MongoDB 自带的 mongo
命令行工具连接到运行中的 MongoDB 实例。在命令行中运行 mongo
命令,如果 MongoDB 运行在本地默认端口(27017),则会直接连接到本地数据库。如果 MongoDB 运行在其他主机或端口,可以使用以下命令连接:
mongo <主机地址>:<端口号>
例如,连接到运行在 192.168.1.100
主机上,端口为 27018
的 MongoDB 实例:
mongo 192.168.1.100:27018
连接成功后,会进入 mongo
命令行界面,显示类似以下的提示符:
MongoDB shell version v6.0.3
connecting to: mongodb://127.0.0.1:27017/?directConnection = true&serverSelectionTimeoutMS = 2000&appName = mongosh + 1.6.1
Implicit session: session { "id": UUID("660c2974 - 4e68 - 4a65 - 9c49 - 99d996c37d16") }
MongoDB server version: 6.0.3
>
3.2 创建数据库和集合
在 MongoDB 中,数据库和集合是在插入文档时自动创建的。例如,要创建一个名为 testdb
的数据库,并在其中创建一个名为 testcollection
的集合,可以使用以下代码:
use testdb
db.testcollection.insertOne({ "name": "First Document" })
在上述代码中,use testdb
命令用于切换到 testdb
数据库,如果该数据库不存在,则会在插入文档时自动创建。db.testcollection.insertOne({ "name": "First Document" })
命令用于向 testcollection
集合中插入一个文档,同时如果 testcollection
集合不存在,也会自动创建。
3.3 插入文档
- 插入单个文档:使用
insertOne
方法插入单个文档。例如,向users
集合中插入一个用户文档:
db.users.insertOne({
"name": "Charlie",
"age": 28,
"email": "charlie@example.com"
})
插入成功后,insertOne
方法会返回一个包含插入文档的 _id
的对象,例如:
{
"acknowledged": true,
"insertedId": ObjectId("6459d89a2d96c1475c59e193")
}
_id
是 MongoDB 为每个文档自动生成的唯一标识符,如果在插入文档时没有指定 _id
,MongoDB 会自动生成一个 ObjectId 类型的 _id
。
- 插入多个文档:使用
insertMany
方法插入多个文档。例如,向products
集合中插入多个产品文档:
db.products.insertMany([
{ "name": "Product 1", "price": 10.99 },
{ "name": "Product 2", "price": 19.99 },
{ "name": "Product 3", "price": 5.99 }
])
insertMany
方法返回一个包含插入结果的对象,其中包含插入的文档数量和每个文档的 _id
:
{
"acknowledged": true,
"insertedIds": [
ObjectId("6459d90e2d96c1475c59e194"),
ObjectId("6459d90e2d96c1475c59e195"),
ObjectId("6459d90e2d96c1475c59e196")
]
}
3.4 查询文档
- 基本查询:使用
find
方法进行基本查询。例如,查询users
集合中所有年龄大于 25 岁的用户:
db.users.find({ "age": { $gt: 25 } })
上述代码中,$gt
是一个比较操作符,表示“大于”。find
方法返回匹配条件的文档游标,可以使用 pretty()
方法格式化输出结果:
db.users.find({ "age": { $gt: 25 } }).pretty()
- 投影查询:可以指定返回文档的字段,实现投影查询。例如,只查询用户的姓名和邮箱,不返回年龄:
db.users.find({ }, { "name": 1, "email": 1, "_id": 0 })
在投影中,指定为 1
的字段表示包含该字段,指定为 0
的字段表示排除该字段。_id
字段默认会包含在结果中,如果不想返回 _id
字段,需要显式指定 _id: 0
。
3.5 更新文档
- 更新单个文档:使用
updateOne
方法更新单个文档。例如,将users
集合中姓名为Charlie
的用户年龄更新为 29 岁:
db.users.updateOne(
{ "name": "Charlie" },
{ $set: { "age": 29 } }
)
updateOne
方法的第一个参数是查询条件,用于确定要更新的文档;第二个参数使用 $set
操作符指定要更新的字段和新的值。
- 更新多个文档:使用
updateMany
方法更新多个文档。例如,将products
集合中所有价格小于 10 的产品价格提高 10%:
db.products.updateMany(
{ "price": { $lt: 10 } },
{ $mul: { "price": 1.1 } }
)
这里使用 $mul
操作符对匹配的文档的 price
字段进行乘法运算,实现价格提高 10%。
3.6 删除文档
- 删除单个文档:使用
deleteOne
方法删除单个文档。例如,删除users
集合中姓名为Charlie
的用户:
db.users.deleteOne({ "name": "Charlie" })
deleteOne
方法的参数是查询条件,用于确定要删除的文档。
- 删除多个文档:使用
deleteMany
方法删除多个文档。例如,删除products
集合中所有价格大于 50 的产品:
db.products.deleteMany({ "price": { $gt: 50 } })
四、MongoDB 索引管理
4.1 索引的概念
索引在 MongoDB 中类似于书籍的目录,它可以加速查询操作。通过在一个或多个字段上创建索引,MongoDB 可以更快地定位到符合查询条件的文档,而不必扫描整个集合。例如,如果经常根据用户的邮箱查询用户文档,在 email
字段上创建索引可以显著提高查询性能。
4.2 创建索引
- 单字段索引:使用
createIndex
方法在单个字段上创建索引。例如,在users
集合的email
字段上创建索引:
db.users.createIndex({ "email": 1 })
这里的 1
表示升序索引,如果使用 -1
则表示降序索引。
- 复合索引:在多个字段上创建复合索引。例如,在
orders
集合的customer_id
和order_date
字段上创建复合索引:
db.orders.createIndex({ "customer_id": 1, "order_date": -1 })
复合索引的顺序很重要,查询条件与索引字段顺序匹配时,索引才能发挥最佳效果。
4.3 查看索引
使用 getIndexes
方法可以查看集合上的所有索引。例如,查看 users
集合的索引:
db.users.getIndexes()
返回结果类似以下格式:
[
{
"v": 2,
"key": {
"_id": 1
},
"name": "_id_",
"ns": "testdb.users"
},
{
"v": 2,
"key": {
"email": 1
},
"name": "email_1",
"ns": "testdb.users"
}
]
每个索引文档包含索引版本(v
)、索引键(key
)、索引名称(name
)和所属集合(ns
)等信息。
4.4 删除索引
使用 dropIndex
方法删除索引。例如,删除 users
集合上名为 email_1
的索引:
db.users.dropIndex("email_1")
也可以使用索引键对象来删除索引,例如:
db.users.dropIndex({ "email": 1 })
五、MongoDB 聚合操作
5.1 聚合的概念
聚合操作允许对数据进行分组、统计、转换等复杂操作,类似于关系型数据库中的 GROUP BY
、SUM
、AVG
等操作。MongoDB 的聚合框架使用管道(pipeline)的概念,将多个操作连接在一起,每个操作处理前一个操作的输出,并将结果传递给下一个操作。
5.2 聚合管道操作符
- $match:用于过滤文档,只允许符合条件的文档进入下一个管道阶段。例如,在
orders
集合中筛选出金额大于 100 的订单:
db.orders.aggregate([
{ $match: { "amount": { $gt: 100 } } }
])
- $group:用于分组文档,并对每个组进行统计操作。例如,按客户 ID 分组订单,并计算每个客户的订单总金额:
db.orders.aggregate([
{ $group: {
_id: "$customer_id",
total_amount: { $sum: "$amount" }
} }
])
在 $group
操作中,_id
字段指定分组的依据,这里使用 $customer_id
表示按 customer_id
字段分组。total_amount
字段使用 $sum
操作符计算每个组的 amount
字段总和。
- $project:用于投影操作,选择要包含在输出文档中的字段。例如,在聚合结果中只保留客户 ID 和订单总金额,并将字段名改为更友好的名称:
db.orders.aggregate([
{ $group: {
_id: "$customer_id",
total_amount: { $sum: "$amount" }
} },
{ $project: {
customer_id: "$_id",
total_amount: 1,
_id: 0
} }
])
这里将 _id
重命名为 customer_id
,并排除 _id
字段。
5.3 复杂聚合示例
假设 products
集合包含产品的名称、价格和类别信息,要计算每个类别的产品平均价格,并筛选出平均价格大于 50 的类别,可以使用以下聚合操作:
db.products.aggregate([
{ $group: {
_id: "$category",
average_price: { $avg: "$price" }
} },
{ $match: { "average_price": { $gt: 50 } } },
{ $project: {
category: "$_id",
average_price: 1,
_id: 0
} }
])
这个聚合操作首先按类别分组产品,计算每个类别的平均价格;然后筛选出平均价格大于 50 的类别;最后投影输出类别和平均价格,排除 _id
字段。
六、MongoDB 备份与恢复
6.1 备份
- 使用 mongodump 工具:
mongodump
工具用于备份 MongoDB 数据库。可以在命令行中运行以下命令备份整个数据库:
mongodump --uri="mongodb://127.0.0.1:27017"
上述命令会在当前目录下创建一个 dump
目录,并将数据库中的所有数据备份到该目录中。如果要备份特定的数据库,可以使用 --db
选项,例如备份 testdb
数据库:
mongodump --uri="mongodb://127.0.0.1:27017" --db testdb
如果要备份特定的集合,可以使用 --collection
选项,例如备份 testdb
数据库中的 users
集合:
mongodump --uri="mongodb://127.0.0.1:27017" --db testdb --collection users
6.2 恢复
- 使用 mongorestore 工具:
mongorestore
工具用于恢复 MongoDB 备份。要恢复之前备份的数据库,可以在命令行中运行以下命令:
mongorestore --uri="mongodb://127.0.0.1:27017" dump
这里的 dump
是 mongodump
生成的备份目录。如果要恢复特定的数据库,可以使用 --db
选项,例如恢复 testdb
数据库:
mongorestore --uri="mongodb://127.0.0.1:27017" --db testdb dump/testdb
如果要恢复特定的集合,可以使用 --collection
选项,例如恢复 testdb
数据库中的 users
集合:
mongorestore --uri="mongodb://127.0.0.1:27017" --db testdb --collection users dump/testdb/users.bson
七、MongoDB 安全管理
7.1 用户管理
- 创建用户:在 MongoDB 中,可以使用
createUser
方法创建用户。例如,在admin
数据库中创建一个具有管理员权限的用户:
use admin
db.createUser({
user: "adminuser",
pwd: "password123",
roles: [ { role: "root", db: "admin" } ]
})
这里创建了一个名为 adminuser
的用户,密码为 password123
,并赋予其 root
角色,该角色在 admin
数据库中具有最高权限。
- 查看用户:使用
getUsers
方法可以查看数据库中的用户。例如,查看admin
数据库中的用户:
use admin
db.getUsers()
- 修改用户密码:使用
updateUser
方法修改用户密码。例如,修改adminuser
的密码:
use admin
db.updateUser("adminuser", { pwd: "newpassword456" })
- 删除用户:使用
dropUser
方法删除用户。例如,删除adminuser
:
use admin
db.dropUser("adminuser")
7.2 身份验证
为了启用身份验证,需要在 MongoDB 的配置文件(通常是 mongod.cfg
)中添加以下配置:
security:
authorization: enabled
然后重启 MongoDB 服务。之后,连接 MongoDB 时需要提供用户名和密码。例如,使用 mongo
命令行工具连接时,可以使用以下命令:
mongo --uri="mongodb://adminuser:password123@127.0.0.1:27017/admin"
这里的 adminuser
是用户名,password123
是密码,admin
是认证数据库。
7.3 网络安全
- 绑定 IP 地址:在 MongoDB 配置文件中,可以通过
net.bindIp
选项指定 MongoDB 监听的 IP 地址。例如,只监听本地回环地址127.0.0.1
:
net:
bindIp: 127.0.0.1
这样可以防止 MongoDB 暴露在公网上,提高安全性。
- 防火墙设置:可以使用操作系统的防火墙工具(如
iptables
在 Linux 上)限制对 MongoDB 端口(默认 27017)的访问。例如,在 Linux 上只允许特定 IP 地址访问 MongoDB 端口:
iptables -A INPUT -p tcp --dport 27017 -s 192.168.1.100 -j ACCEPT
iptables -A INPUT -p tcp --dport 27017 -j DROP
上述命令允许 192.168.1.100
访问 MongoDB 端口,拒绝其他所有 IP 地址访问。
通过以上对 MongoDB 数据库管理基础的介绍,涵盖了从基础概念到实际操作、索引管理、聚合操作、备份恢复以及安全管理等方面的内容,希望能帮助读者全面掌握 MongoDB 的基本管理技能,为进一步深入使用 MongoDB 打下坚实的基础。在实际应用中,还需要根据具体的业务需求和场景,灵活运用这些知识,充分发挥 MongoDB 的优势。