跳转到内容

MongoDB文档数据库

课程目标

  • 了解MongoDB的基本概念和特点
  • 掌握MongoDB的安装和配置方法
  • 熟悉MongoDB的CRUD操作
  • 了解MongoDB的查询和索引优化
  • 掌握MongoDB的聚合操作
  • 了解MongoDB的事务支持
  • 掌握MongoDB的高可用性方案
  • 学习MongoDB的性能优化技巧
  • 掌握MongoDB与Python和Go的集成

1. MongoDB简介

1.1 什么是MongoDB

MongoDB是一个开源的、面向文档的NoSQL数据库,由MongoDB Inc.开发和维护。它使用BSON(Binary JSON)格式存储数据,提供了灵活的数据模型和强大的查询能力。

1.2 MongoDB的特点

  • 文档模型:使用类似JSON的BSON格式存储数据,支持嵌套文档和数组
  • 灵活的模式:不需要预定义表结构,字段可以动态添加和修改
  • 强大的查询语言:支持丰富的查询操作,包括范围查询、正则表达式、聚合等
  • 索引支持:支持各种类型的索引,包括单字段索引、复合索引、地理空间索引等
  • 高可用性:通过复制集实现数据冗余和自动故障转移
  • 水平扩展性:通过分片机制支持大规模数据存储
  • 事务支持:从4.0版本开始支持多文档事务
  • 丰富的生态系统:提供多种语言的驱动程序和工具

1.3 MongoDB的应用场景

  • 内容管理系统:灵活的文档模型适合存储各种类型的内容
  • 移动应用后端:支持快速开发和迭代
  • 实时分析:强大的聚合功能适合数据分析
  • IoT应用:可以处理大量的传感器数据
  • 电商平台:支持复杂的产品信息和用户行为数据
  • 游戏应用:适合存储游戏状态和用户数据

2. MongoDB安装和配置

2.1 在Linux上安装MongoDB

Ubuntu/Debian系统

bash
# 导入MongoDB GPG密钥
wget -qO - https://www.mongodb.org/static/pgp/server-7.0.asc | sudo apt-key add -

# 添加MongoDB源
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list

# 更新包列表并安装MongoDB
sudo apt-get update
sudo apt-get install -y mongodb-org

# 启动MongoDB服务
sudo systemctl start mongod
sudo systemctl enable mongod

CentOS/RHEL系统

bash
# 创建MongoDB源文件
sudo tee /etc/yum.repos.d/mongodb-org-7.0.repo << 'EOF'
[mongodb-org-7.0]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/7.0/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-7.0.asc
EOF

# 安装MongoDB
sudo yum install -y mongodb-org

# 启动MongoDB服务
sudo systemctl start mongod
sudo systemctl enable mongod

2.2 基本配置

MongoDB的主要配置文件位于/etc/mongod.conf,可以通过修改此文件来配置MongoDB:

yaml
# mongod.conf

# for documentation of all options, see:
#   http://docs.mongodb.org/manual/reference/configuration-options/

# where to write logging data.
systemLog:
  destination: file
  logAppend: true
  path: /var/log/mongodb/mongod.log

# Where and how to store data.
storage:
  dbPath: /var/lib/mongo
  journal:
    enabled: true

# network interfaces
net:
  port: 27017
  bindIp: 127.0.0.1  # 绑定IP地址,0.0.0.0表示允许所有IP访问

# how the process runs
processManagement:
  timeZoneInfo: /usr/share/zoneinfo

# security:
#   authorization: enabled  # 启用身份验证

# operationProfiling:

# replication:

# sharding:

## Enterprise-Only Options:

# auditLog:

# snmp:

2.3 启动和停止MongoDB

bash
# 启动MongoDB
sudo systemctl start mongod

# 停止MongoDB
sudo systemctl stop mongod

# 重启MongoDB
sudo systemctl restart mongod

# 查看MongoDB状态
sudo systemctl status mongod

2.4 连接到MongoDB

bash
# 使用mongo shell连接
sudo mongosh

# 连接到指定主机和端口
mongosh --host 127.0.0.1 --port 27017

# 使用认证连接
mongosh --host 127.0.0.1 --port 27017 -u admin -p password --authenticationDatabase admin

3. MongoDB基本概念

3.1 数据库(Database)

数据库是集合的容器,一个MongoDB实例可以包含多个数据库。默认的数据库是test

3.2 集合(Collection)

集合是文档的容器,相当于关系型数据库中的表。集合不需要预定义结构,可以存储不同结构的文档。

3.3 文档(Document)

文档是MongoDB中最基本的数据单位,相当于关系型数据库中的行。文档使用BSON格式存储,类似于JSON格式。

3.4 字段(Field)

字段是文档中的键值对,相当于关系型数据库中的列。

3.5 示例文档

json
{
  "_id": ObjectId("60c72b9e9b1b2c3d4e5f6a7b"),
  "name": "张三",
  "age": 30,
  "email": "zhangsan@example.com",
  "address": {
    "city": "北京",
    "district": "朝阳区",
    "street": "建国路88号"
  },
  "hobbies": ["阅读", "旅游", "健身"],
  "created_at": ISODate("2023-06-14T08:30:00Z")
}

4. MongoDB CRUD操作

4.1 创建文档(Create)

javascript
// 插入单个文档
db.users.insertOne({
  name: "李四",
  age: 25,
  email: "lisi@example.com",
  address: {
    city: "上海",
    district: "浦东新区"
  },
  hobbies: ["音乐", "电影"]
});

// 插入多个文档
db.users.insertMany([
  {
    name: "王五",
    age: 35,
    email: "wangwu@example.com",
    address: {
      city: "广州",
      district: "天河区"
    },
    hobbies: ["美食", "摄影"]
  },
  {
    name: "赵六",
    age: 28,
    email: "zhaoliu@example.com",
    address: {
      city: "深圳",
      district: "南山区"
    },
    hobbies: ["编程", "游戏"]
  }
]);

4.2 读取文档(Read)

javascript
// 查询所有文档
db.users.find();

// 查询单个文档
db.users.findOne({ name: "李四" });

// 条件查询
db.users.find({ age: { $gt: 25 } });  // 年龄大于25的用户

// 投影查询(只返回指定字段)
db.users.find({ age: { $gt: 25 } }, { name: 1, age: 1, _id: 0 });

// 排序查询
db.users.find().sort({ age: 1 });  // 按年龄升序排序

// 限制查询结果数量
db.users.find().limit(5);

// 跳过指定数量的结果
db.users.find().skip(5);

4.3 更新文档(Update)

javascript
// 更新单个文档
db.users.updateOne(
  { name: "李四" },
  {
    $set: { age: 26, email: "lisi_new@example.com" },
    $currentDate: { updated_at: true }
  }
);

// 更新多个文档
db.users.updateMany(
  { age: { $lt: 30 } },
  {
    $set: { status: "young" }
  }
);

// 替换整个文档
db.users.replaceOne(
  { name: "王五" },
  {
    name: "王五",
    age: 36,
    email: "wangwu_new@example.com",
    address: {
      city: "广州",
      district: "天河区",
      street: "天河路385号"
    }
  }
);

4.4 删除文档(Delete)

javascript
// 删除单个文档
db.users.deleteOne({ name: "赵六" });

// 删除多个文档
db.users.deleteMany({ age: { $gt: 40 } });

// 删除集合中的所有文档
db.users.deleteMany({});

// 删除整个集合
db.users.drop();

5. MongoDB查询和索引

5.1 查询操作符

MongoDB提供了丰富的查询操作符:

操作符描述示例
$eq等于{ age: { $eq: 30 } }
$ne不等于{ age: { $ne: 30 } }
$gt大于{ age: { $gt: 30 } }
$gte大于等于{ age: { $gte: 30 } }
$lt小于{ age: { $lt: 30 } }
$lte小于等于{ age: { $lte: 30 } }
$in在指定数组中{ age: { $in: [25, 30, 35] } }
$nin不在指定数组中{ age: { $nin: [25, 30, 35] } }
$and逻辑与{ $and: [{ age: { $gt: 25 } }, { age: { $lt: 35 } }] }
$or逻辑或{ $or: [{ age: { $lt: 25 } }, { age: { $gt: 35 } }] }
$not逻辑非{ age: { $not: { $gt: 30 } } }
$nor逻辑NOR{ $nor: [{ age: { $lt: 25 } }, { age: { $gt: 35 } }] }
$exists字段存在{ email: { $exists: true } }
$type字段类型{ age: { $type: "int" } }
$regex正则表达式{ name: { $regex: /^张/ } }

5.2 索引类型

MongoDB支持多种类型的索引:

  • 单字段索引:基于单个字段创建的索引
  • 复合索引:基于多个字段创建的索引
  • 多键索引:用于数组字段的索引
  • 地理空间索引:用于地理位置数据的索引
  • 文本索引:用于文本搜索的索引
  • 哈希索引:用于基于哈希值的相等查询

5.3 创建索引

javascript
// 创建单字段索引
db.users.createIndex({ name: 1 });  // 1表示升序,-1表示降序

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

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

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

// 创建地理空间索引
db.places.createIndex({ location: "2dsphere" });

5.4 查看索引

javascript
// 查看集合的所有索引
db.users.getIndexes();

// 查看索引大小
db.users.totalIndexSize();

5.5 删除索引

javascript
// 删除指定索引
db.users.dropIndex("name_1");

// 删除所有索引(除了_id索引)
db.users.dropIndexes();

5.6 查询计划

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

// 查看详细的执行统计
db.users.explain("executionStats").find({ age: { $gt: 30 } });

6. MongoDB聚合操作

6.1 聚合管道

聚合管道是MongoDB中用于数据处理和分析的强大工具,它由多个阶段组成,每个阶段对数据进行特定的处理。

6.2 常用聚合阶段

阶段描述示例
$match过滤文档{ $match: { age: { $gt: 30 } } }
$project重塑文档结构{ $project: { name: 1, age: 1, _id: 0 } }
$group分组文档{ $group: { _id: "$address.city", count: { $sum: 1 } } }
$sort排序文档{ $sort: { count: -1 } }
$limit限制结果数量{ $limit: 5 }
$skip跳过文档{ $skip: 5 }
$unwind展开数组{ $unwind: "$hobbies" }
$lookup左外连接{ $lookup: { from: "orders", localField: "_id", foreignField: "user_id", as: "orders" } }
$addFields添加字段{ $addFields: { fullName: { $concat: ["$firstName", " ", "$lastName"] } } }
$replaceRoot替换根文档{ $replaceRoot: { newRoot: "$address" } }

6.3 聚合示例

6.3.1 按城市分组统计用户数量

javascript
db.users.aggregate([
  { $match: { age: { $gt: 25 } } },
  { $group: { _id: "$address.city", count: { $sum: 1 } } },
  { $sort: { count: -1 } },
  { $limit: 10 }
]);

6.3.2 计算每个用户的 hobbies 数量

javascript
db.users.aggregate([
  { $project: { name: 1, hobbies_count: { $size: "$hobbies" } } },
  { $sort: { hobbies_count: -1 } }
]);

6.3.3 连接用户和订单数据

javascript
db.users.aggregate([
  { $match: { age: { $gt: 30 } } },
  { $lookup: {
      from: "orders",
      localField: "_id",
      foreignField: "user_id",
      as: "orders"
    }
  },
  { $addFields: { order_count: { $size: "$orders" } } },
  { $match: { order_count: { $gt: 0 } } },
  { $sort: { order_count: -1 } }
]);

7. MongoDB事务支持

7.1 事务概述

MongoDB从4.0版本开始支持多文档事务,4.2版本开始支持分布式事务(跨分片的事务)。事务允许将多个操作作为一个原子单元执行,要么全部成功,要么全部失败。

7.2 事务使用场景

  • 金融交易:确保资金转移的原子性
  • 订单处理:确保订单创建和库存更新的一致性
  • 用户数据更新:确保相关数据的一致性更新

7.3 事务操作

javascript
// 启动事务
session = db.getMongo().startSession();
try {
  session.startTransaction();
  
  // 执行操作
  db.users.updateOne({ _id: ObjectId("60c72b9e9b1b2c3d4e5f6a7b") }, { $inc: { balance: -100 } });
  db.orders.insertOne({ user_id: ObjectId("60c72b9e9b1b2c3d4e5f6a7b"), amount: 100, status: "pending" });
  
  // 提交事务
  session.commitTransaction();
  print("Transaction committed successfully.");
} catch (error) {
  // 回滚事务
  session.abortTransaction();
  print("Transaction aborted due to error:", error);
} finally {
  session.endSession();
}

7.4 事务注意事项

  • 性能影响:事务会锁定相关资源,可能影响并发性能
  • 操作限制:事务中的操作有一些限制,如不能创建集合、不能修改索引等
  • 超时设置:事务有默认的超时时间,超过时间会自动中止
  • 内存限制:事务使用的内存有限制,大型事务可能会失败

8. MongoDB高可用性

8.1 复制集(Replica Set)

复制集是MongoDB实现高可用性的主要方式,它由多个MongoDB实例组成,包括一个主节点(Primary)和多个从节点(Secondary)。

8.1.1 复制集的作用

  • 数据冗余:多个节点存储相同的数据副本
  • 自动故障转移:当主节点故障时,自动选举新的主节点
  • 读写分离:读操作可以分发到从节点,提高读取性能

8.1.2 复制集架构

  • 主节点(Primary):接收所有写操作,将操作记录到 oplog 中
  • 从节点(Secondary):复制主节点的 oplog 并应用到本地,保持数据同步
  • 仲裁节点(Arbiter):不存储数据,只参与选举投票

8.1.3 配置复制集

javascript
// 初始化复制集
rs.initiate({
  _id: "myReplicaSet",
  members: [
    { _id: 0, host: "mongodb1:27017" },
    { _id: 1, host: "mongodb2:27017" },
    { _id: 2, host: "mongodb3:27017", arbiterOnly: true }
  ]
});

// 查看复制集状态
rs.status();

// 添加节点
rs.add("mongodb4:27017");

// 移除节点
rs.remove("mongodb4:27017");

// 查看复制延迟
rs.printSlaveReplicationInfo();

8.2 分片(Sharding)

分片是MongoDB实现水平扩展的方式,它将数据分散存储在多个分片服务器上。

8.2.1 分片架构

  • 分片服务器(Shard):存储部分数据的MongoDB实例,通常是复制集
  • 配置服务器(Config Server):存储分片集群的元数据和配置信息
  • 路由服务器(Mongos):作为客户端的接入点,负责将请求路由到相应的分片

8.2.2 分片键

分片键是用于确定数据分布的字段,选择合适的分片键非常重要。

8.2.3 配置分片集群

javascript
// 启动配置服务器
mongod --configsvr --replSet configReplSet --port 27019 --dbpath /data/configdb

// 初始化配置服务器复制集
rs.initiate({
  _id: "configReplSet",
  members: [
    { _id: 0, host: "config1:27019" },
    { _id: 1, host: "config2:27019" },
    { _id: 2, host: "config3:27019" }
  ]
});

// 启动路由服务器
mongos --configdb configReplSet/config1:27019,config2:27019,config3:27019 --port 27017

// 启动分片服务器
mongod --shardsvr --replSet shard1ReplSet --port 27018 --dbpath /data/shard1
mongod --shardsvr --replSet shard2ReplSet --port 27020 --dbpath /data/shard2

// 初始化分片复制集
rs.initiate({
  _id: "shard1ReplSet",
  members: [
    { _id: 0, host: "shard1:27018" }
  ]
});

rs.initiate({
  _id: "shard2ReplSet",
  members: [
    { _id: 0, host: "shard2:27020" }
  ]
});

// 添加分片到集群
sh.addShard("shard1ReplSet/shard1:27018");
sh.addShard("shard2ReplSet/shard2:27020");

// 启用数据库分片
sh.enableSharding("mydb");

// 集合分片(指定分片键)
sh.shardCollection("mydb.users", { "_id": "hashed" });

9. MongoDB性能优化

9.1 查询优化

  • 使用索引:为常用查询字段创建索引
  • 避免全表扫描:使用索引覆盖查询
  • 限制返回字段:使用投影减少数据传输
  • 限制结果数量:使用 limit 减少数据处理
  • 避免使用 $where:$where 操作符会降低查询性能
  • 使用聚合管道:对于复杂查询,使用聚合管道代替多次查询

9.2 写入优化

  • 批量写入:使用 insertMany 批量插入文档
  • 使用 unordered 写入:允许部分写入失败,提高性能
  • 避免创建过多索引:索引会影响写入性能
  • 使用 WriteConcern:根据业务需求设置合适的写入确认级别
  • 预分配空间:使用 db.adminCommand({ setParameter: 1, internalQueryExecMaxBlockingSortBytes: <value> }) 预分配空间

9.3 存储优化

  • 使用 WiredTiger 存储引擎:WiredTiger 提供更好的压缩和并发性能
  • 启用压缩:WiredTiger 支持 Snappy 和 zlib 压缩
  • 合理设置集合大小:避免单个集合过大
  • 使用 capped collections:对于日志等只追加的数据,使用 capped collections
  • 定期归档数据:对于历史数据,进行归档处理

9.4 内存优化

  • 合理设置 WiredTiger 缓存大小:默认是 RAM 的 50%
  • 使用索引覆盖查询:减少内存使用
  • 限制结果集大小:避免一次性加载过多数据到内存
  • 使用游标:对于大型结果集,使用游标分批处理

9.5 监控和诊断

  • 使用 mongostat:监控 MongoDB 实例的状态
  • 使用 mongotop:监控集合级别的操作延迟
  • 使用 db.serverStatus():查看服务器状态
  • 使用 db.collection.stats():查看集合统计信息
  • 使用慢查询日志:识别性能问题

10. MongoDB最佳实践

10.1 数据建模

  • 使用嵌入文档:对于一对一和一对多关系,优先使用嵌入文档
  • 使用引用:对于多对多关系,使用引用
  • 避免深层嵌套:嵌套层级不宜过深,一般不超过3-4层
  • 合理使用数组:对于数量有限的数组,使用数组字段
  • 考虑查询模式:根据查询模式设计数据模型

10.2 安全性

  • 启用身份验证:设置用户名和密码
  • 配置访问控制:使用角色-based访问控制
  • 加密传输:使用 SSL/TLS 加密网络传输
  • 加密存储:使用存储加密保护数据
  • 定期备份:制定备份策略

10.3 部署建议

  • 使用复制集:至少部署3个节点的复制集
  • 使用分片:对于大型数据集,使用分片集群
  • 合理设置硬件:根据负载选择合适的硬件
  • 监控系统:使用监控工具监控 MongoDB 实例
  • 定期维护:定期进行索引重建、数据压缩等维护操作

10.4 应用开发

  • 使用连接池:重用数据库连接
  • 处理连接错误:实现重连机制
  • 使用批量操作:减少网络往返
  • 合理设置超时:避免长时间阻塞
  • 使用事务:对于需要原子性的操作,使用事务

11. MongoDB与Python集成

11.1 安装PyMongo

bash
pip install pymongo

11.2 Python连接MongoDB

python
from pymongo import MongoClient

# 连接到MongoDB
client = MongoClient('mongodb://localhost:27017/')

# 选择数据库
db = client['mydb']

# 选择集合
users_collection = db['users']

11.3 Python CRUD操作

python
# 插入文档
user = {
    "name": "张三",
    "age": 30,
    "email": "zhangsan@example.com",
    "address": {
        "city": "北京",
        "district": "朝阳区"
    },
    "hobbies": ["阅读", "旅游"]
}
result = users_collection.insert_one(user)
print(f"插入的文档ID: {result.inserted_id}")

# 查询文档
# 查询单个文档
user = users_collection.find_one({"name": "张三"})
print(f"查询结果: {user}")

# 查询多个文档
users = users_collection.find({"age": {"$gt": 25}})
for user in users:
    print(user)

# 更新文档
result = users_collection.update_one(
    {"name": "张三"},
    {"$set": {"age": 31, "email": "zhangsan_new@example.com"}}
)
print(f"更新的文档数: {result.modified_count}")

# 删除文档
result = users_collection.delete_one({"name": "张三"})
print(f"删除的文档数: {result.deleted_count}")

11.4 Python聚合操作

python
# 聚合操作
pipeline = [
    {"$match": {"age": {"$gt": 25}}},
    {"$group": {"_id": "$address.city", "count": {"$sum": 1}}},
    {"$sort": {"count": -1}},
    {"$limit": 5}
]

result = list(users_collection.aggregate(pipeline))
print("聚合结果:")
for item in result:
    print(item)

11.5 Python事务操作

python
# 事务操作
from pymongo import MongoClient
from pymongo.errors import PyMongoError

client = MongoClient('mongodb://localhost:27017/')
db = client['mydb']
users_collection = db['users']
orders_collection = db['orders']

# 启动会话
session = client.start_session()
try:
    # 开始事务
    with session.start_transaction():
        # 更新用户余额
        users_collection.update_one(
            {"_id": user_id},
            {"$inc": {"balance": -100}},
            session=session
        )
        # 创建订单
        order = {
            "user_id": user_id,
            "amount": 100,
            "status": "pending",
            "created_at": datetime.now()
        }
        orders_collection.insert_one(order, session=session)
    print("事务执行成功")
except PyMongoError as e:
    print(f"事务执行失败: {e}")
finally:
    # 结束会话
    session.end_session()

12. MongoDB与Go集成

12.1 安装MongoDB Go驱动

bash
go get go.mongodb.org/mongo-driver/mongo
go get go.mongodb.org/mongo-driver/bson
go get go.mongodb.org/mongo-driver/mongo/options

12.2 Go连接MongoDB

go
package main

import (
	"context"
	"fmt"
	"log"

	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

func main() {
	// 设置客户端选项
	clientOptions := options.Client().ApplyURI("mongodb://localhost:27017/")

	// 连接到MongoDB
	client, err := mongo.Connect(context.Background(), clientOptions)
	if err != nil {
		log.Fatal(err)
	}

	// 检查连接
	err = client.Ping(context.Background(), nil)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("成功连接到MongoDB")

	// 选择数据库和集合
	db := client.Database("mydb")
	collection := db.Collection("users")

	// 关闭连接
	defer client.Disconnect(context.Background())
}

12.3 Go CRUD操作

go
package main

import (
	"context"
	"fmt"
	"log"
	"time"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

// User 结构体
type User struct {
	ID        primitive.ObjectID `bson:"_id,omitempty" json:"id"`
	Name      string             `bson:"name" json:"name"`
	Age       int                `bson:"age" json:"age"`
	Email     string             `bson:"email" json:"email"`
	Address   Address            `bson:"address" json:"address"`
	Hobbies   []string           `bson:"hobbies" json:"hobbies"`
	CreatedAt time.Time          `bson:"created_at" json:"created_at"`
}

// Address 结构体
type Address struct {
	City     string `bson:"city" json:"city"`
	District string `bson:"district" json:"district"`
}

func main() {
	// 连接到MongoDB
	clientOptions := options.Client().ApplyURI("mongodb://localhost:27017/")
	client, err := mongo.Connect(context.Background(), clientOptions)
	if err != nil {
		log.Fatal(err)
	}
	defer client.Disconnect(context.Background())

	db := client.Database("mydb")
	collection := db.Collection("users")
	ctx := context.Background()

	// 插入文档
	user := User{
		Name:  "李四",
		Age:   25,
		Email: "lisi@example.com",
		Address: Address{
			City:     "上海",
			District: "浦东新区",
		},
		Hobbies:   []string{"音乐", "电影"},
		CreatedAt: time.Now(),
	}

	result, err := collection.InsertOne(ctx, user)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("插入的文档ID: %v\n", result.InsertedID)

	// 查询文档
	// 查询单个文档
	var foundUser User
	err = collection.FindOne(ctx, bson.M{"name": "李四"}).Decode(&foundUser)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("查询结果: %+v\n", foundUser)

	// 查询多个文档
	cursor, err := collection.Find(ctx, bson.M{"age": bson.M{"$gt": 20}})
	if err != nil {
		log.Fatal(err)
	}
	defer cursor.Close(ctx)

	var users []User
	if err = cursor.All(ctx, &users); err != nil {
		log.Fatal(err)
	}
	fmt.Println("查询多个文档结果:")
	for _, u := range users {
		fmt.Printf("%+v\n", u)
	}

	// 更新文档
	updateResult, err := collection.UpdateOne(
		ctx,
		bson.M{"name": "李四"},
		bson.M{"$set": bson.M{"age": 26, "email": "lisi_new@example.com"}},
	)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("更新的文档数: %v\n", updateResult.ModifiedCount)

	// 删除文档
	deleteResult, err := collection.DeleteOne(ctx, bson.M{"name": "李四"})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("删除的文档数: %v\n", deleteResult.DeletedCount)
}

12.4 Go聚合操作

go
package main

import (
	"context"
	"fmt"
	"log"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

func main() {
	// 连接到MongoDB
	clientOptions := options.Client().ApplyURI("mongodb://localhost:27017/")
	client, err := mongo.Connect(context.Background(), clientOptions)
	if err != nil {
		log.Fatal(err)
	}
	defer client.Disconnect(context.Background())

	db := client.Database("mydb")
	collection := db.Collection("users")
	ctx := context.Background()

	// 聚合操作
	pipeline := mongo.Pipeline{
		bson.D{{"$match", bson.D{{"age", bson.D{{"$gt", 25}}}}}},
		bson.D{{"$group", bson.D{{"_id", "$address.city"}, {"count", bson.D{{"$sum", 1}}}}}},
		bson.D{{"$sort", bson.D{{"count", -1}}}},
		bson.D{{"$limit", 5}},
	}

	cursor, err := collection.Aggregate(ctx, pipeline)
	if err != nil {
		log.Fatal(err)
	}
	defer cursor.Close(ctx)

	var results []bson.M
	if err = cursor.All(ctx, &results); err != nil {
		log.Fatal(err)
	}

	fmt.Println("聚合结果:")
	for _, result := range results {
		fmt.Printf("%+v\n", result)
	}
}

13. 课程总结

13.1 关键知识点

  • MongoDB是一个面向文档的NoSQL数据库,使用BSON格式存储数据
  • MongoDB的基本概念包括数据库、集合、文档和字段
  • MongoDB支持丰富的CRUD操作和查询操作符
  • MongoDB提供多种类型的索引,以提高查询性能
  • MongoDB的聚合管道功能强大,适合数据分析
  • MongoDB支持多文档事务,确保数据一致性
  • MongoDB通过复制集实现高可用性,通过分片实现水平扩展性
  • MongoDB的性能优化包括查询优化、写入优化、存储优化和内存优化
  • MongoDB与Python和Go等语言有良好的集成支持

13.2 学习建议

  • 动手实践:安装MongoDB并进行实际操作
  • 深入理解:理解MongoDB的数据模型和查询机制
  • 掌握索引:学习如何创建和使用索引
  • 学习聚合:掌握聚合管道的使用
  • 了解高可用:学习复制集和分片的配置
  • 实践项目:在实际项目中使用MongoDB
  • 持续学习:关注MongoDB的新版本和新特性

13.3 参考资源

通过本课程的学习,你应该已经掌握了MongoDB的基本概念和使用方法,能够在实际项目中应用MongoDB进行数据存储和管理。MongoDB作为一款强大的NoSQL数据库,在现代应用开发中有着广泛的应用,掌握它将为你的技术栈增添重要的一环。

评论区

专业的Linux技术学习平台,从入门到精通的完整学习路径