🍃

MongoDB 完全学习指南

最流行的NoSQL文档数据库

📄 文档数据库 ⚡ 高性能 📈 水平扩展 🔄 副本集 🌐 JSON存储

📖 MongoDB 简介

MongoDB是一个面向文档的NoSQL数据库管理系统,使用BSON格式存储数据,非常适合存储非结构化或半结构化数据。

✨ 核心特性

  • ✅ JSON-like文档存储
  • ✅ 灵活的Schema设计
  • ✅ 强大的查询语言
  • ✅ 自动分片水平扩展
  • ✅ 副本集高可用
  • ✅ 丰富的索引类型

🎯 应用场景

  • 📱 移动应用后端
  • 📊 实时分析和大数据
  • 🛒 电商和内容管理
  • 👤 用户行为追踪
  • 📝 日志和事件存储
  • 🌐 IoT物联网应用

📊 与传统数据库对比

特性 MongoDB 关系数据库
数据模型 文档(BSON) 表(行/列)
Schema 灵活,动态 固定,需预定义
查询语言 JavaScript类似 SQL
关系处理 嵌入或引用 Join操作
扩展性 水平扩展(分片) 垂直扩展

🔧 MongoDB 安装和配置

🍎 macOS 安装

# 使用 Homebrew
brew tap mongodb/brew
brew install mongodb-community

# 启动服务
brew services start mongodb-community

# 连接
mongosh

# Docker方式
docker run -d -p 27017:27017 --name mongodb mongo:latest
docker exec -it mongodb mongosh

🐧 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

⚙️ 配置文件 mongod.conf

storage:
  dbPath: /var/lib/mongodb
  journal:
    enabled: true

systemLog:
  destination: file
  logAppend: true
  path: /var/log/mongodb/mongod.log
  logRotate: reopen

net:
  port: 27017
  bindIp: 127.0.0.1

processManagement:
  fork: true
  pidFilePath: /var/run/mongodb/mongod.pid

security:
  authorization: enabled

配置文件位置:/etc/mongod.conf

💡 MongoDB 基础操作

🏗️ 数据库操作

// 显示所有数据库
show dbs

// 切换/创建数据库
use myapp

// 查看当前数据库
db

// 查看数据库状态
db.stats()

// 删除数据库
db.dropDatabase()

📝 集合和文档操作

// 创建集合(显式)
db.createCollection("users")

// 插入单个文档
db.users.insertOne({
  name: "John",
  age: 30,
  email: "john@example.com",
  city: "New York"
})

// 插入多个文档
db.users.insertMany([
  { name: "Alice", age: 25, email: "alice@example.com" },
  { name: "Bob", age: 35, email: "bob@example.com" }
])

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

// 条件查询
db.users.find({ age: { $gte: 25 } })
db.users.find({ name: /^A/ })  // 正则

// 查询一个文档
db.users.findOne({ name: "John" })

// 限制和跳过
db.users.find().limit(5).skip(10)

// 排序
db.users.find().sort({ age: -1 })  // -1降序,1升序

✏️ 更新操作

// 更新单个文档
db.users.updateOne(
  { name: "John" },
  { $set: { age: 31, lastLogin: new Date() } }
)

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

// 替换整个文档
db.users.replaceOne(
  { name: "John" },
  { name: "John", age: 32, email: "new@example.com" }
)

// 更新操作符
db.users.updateOne(
  { name: "John" },
  {
    $inc: { age: 1 },              // 增加
    $mul: { age: 2 },                // 乘法
    $rename: { "city": "location" }, // 重命名字段
    $unset: { temp: "" },           // 删除字段
    $push: { hobbies: "reading" },   // 数组添加
    $pull: { hobbies: "reading" }   // 数组移除
  }
)

🗑️ 删除操作

// 删除单个文档
db.users.deleteOne({ name: "John" })

// 删除多个文档
db.users.deleteMany({ age: { $lt: 18 } })

// 删除所有文档
db.users.deleteMany({})

// 删除集合
db.users.drop()

📚 索引

// 创建单字段索引
db.users.createIndex({ email: 1 })
db.users.createIndex({ age: -1 })  // -1降序

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

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

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

// 创建TTL索引(自动删除过期文档)
db.sessions.createIndex(
  { createdAt: 1 },
  { expireAfterSeconds: 3600 }
)

// 查看索引
db.users.getIndexes()

// 删除索引
db.users.dropIndex({ email: 1 })

// 分析查询性能
db.users.find({ email: "john@example.com" }).explain("executionStats")

⚡ MongoDB 高级特性

🔄 聚合管道

// 基础聚合
db.orders.aggregate([
  { $match: { status: "completed" } },
  { $group: {
    _id: "$customer_id",
    total: { $sum: "$amount" },
    count: { $sum: 1 }
  }},
  { $sort: { total: -1 } },
  { $limit: 10 }
])

// $lookup 关联查询
db.orders.aggregate([
  {
    $lookup: {
      from: "customers",
      localField: "customer_id",
      foreignField: "_id",
      as: "customer_info"
    }
  },
  { $unwind: "$customer_info" },
  { $project: {
    orderId: "$_id",
    amount: 1,
    customerName: "$customer_info.name"
  }}
])

// $facet 多维度分析
db.sales.aggregate([
  {
    $facet: {
      totalSales: [
        { $group: { _id: null, total: { $sum: "$amount" } } }
      ],
      byCategory: [
        { $group: { _id: "$category", total: { $sum: "$amount" } } }
      ],
      byRegion: [
        { $group: { _id: "$region", total: { $sum: "$amount" } } }
      ]
    }
  }
])

💡 常用聚合操作符:

  • • $match - 过滤文档
  • • $group - 分组聚合
  • • $project - 投影字段
  • • $sort - 排序
  • • $limit/$skip - 限制
  • • $unwind - 展开数组
  • • $lookup - 关联查询

🔒 ACID事务

// JavaScript Shell 事务
const session = db.getMongo().startSession();

session.startTransaction();

try {
  const db = session.getDatabase("myapp");
  
  db.accounts.updateOne(
    { _id: 1 },
    { $inc: { balance: -100 } }
  );
  
  db.accounts.updateOne(
    { _id: 2 },
    { $inc: { balance: 100 } }
  );
  
  session.commitTransaction();
} catch (error) {
  session.abortTransaction();
}

// Node.js Driver 示例
const { MongoClient } = require('mongodb');

async function transfer(senderId, receiverId, amount) {
  const session = client.startSession();
  
  try {
    await session.withTransaction(async () => {
      await accounts.updateOne(
        { _id: senderId },
        { $inc: { balance: -amount } },
        { session }
      );
      
      await accounts.updateOne(
        { _id: receiverId },
        { $inc: { balance: amount } },
        { session }
      );
    });
  } finally {
    await session.endSession();
  }
}

📡 Change Streams

// 监听集合变化
const changeStream = db.users.watch();

changeStream.on('change', (change) => {
  console.log('Change detected:', change);
});

// 监听特定操作
db.users.watch([
  { $match: { 'fullDocument.age': { $gte: 25 } } }
], {
  fullDocument: 'updateLookup'
});

// Node.js 实现
const pipeline = [{ $match: { 'fullDocument.status': 'active' } }];
const changeStream = collection.watch(pipeline);

changeStream.on('change', next => {
  console.log('Document changed:', next);
});

// 监听数据库级变化
const dbChangeStream = db.watch();

// 监听集群级变化
const clusterChangeStream = client.watch();

🔄 复制集配置

// 初始化复制集
rs.initiate({
  _id: "rs0",
  members: [
    { _id: 0, host: "localhost:27017" },
    { _id: 1, host: "localhost:27018" },
    { _id: 2, host: "localhost:27019" }
  ]
})

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

// 添加成员
rs.add("localhost:27020")

// 移除成员
rs.remove("localhost:27020")

// 查看配置
rs.conf()

✨ 复制集优势:

  • • 高可用性 - 自动故障转移
  • • 数据冗余 - 多副本备份
  • • 读写分离 - 提高并发性能
  • • 自愈能力 - 自动恢复节点

🚀 MongoDB 性能优化

⚡ 分片策略

✅ 最佳实践

  • • 选择基数高的字段作为分片键
  • • 避免分片键单调递增
  • • 使用复合分片键优化查询
  • • 为副本集节点配置足够的Oplog大小
  • • 定期监控分片平衡状态

❌ 避免的陷阱

  • • 避免热键导致的性能瓶颈
  • • 不要使用低基数字段
  • • 避免分片键频繁更新
  • • 不要忽视索引管理
  • • 避免连接池配置过大

📊 启用分片

// 启动配置服务器(配置服务器副本集)
mongod --configsvr --replSet configReplSet --dbpath /data/configdb --port 27019

// 启动Mongos路由服务器
mongos --configdb configReplSet/localhost:27019 --port 27017

// 添加分片
sh.addShard("shardReplSet/localhost:27018,localhost:27028")

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

// 为集合创建分片
sh.shardCollection("myapp.users", { "user_id": 1 })

// 查看分片状态
sh.status()

// 平衡分片(手动触发)
sh.startBalancer()

🔍 查询优化技巧

// 使用投影只返回需要的字段
db.users.find({ age: { $gt: 25 } }, { name: 1, email: 1 })

// 使用批量操作
db.users.bulkWrite([
  { updateOne: { filter: { name: "A" }, update: { $set: { age: 30 } } } },
  { deleteOne: { filter: { name: "B" } } }
])

// 分析慢查询
db.setProfilingLevel(1, { slowms: 100 })  // 记录>100ms的查询
db.system.profile.find().sort({ ts: -1 }).limit(5)

// 使用 hint 强制索引
db.users.find({ email: "user@example.com" })
  .hint({ email: 1 })

// 使用 $expr 避免索引失效
db.users.find({ $expr: { $gt: ["$balance", "$credit"] } })

// 合理使用 $lookup(避免无索引的Join)
db.orders.aggregate([
  {
    $lookup: {
      from: "users",
      let: { uid: "$user_id" },
      pipeline: [
        { $match: { $expr: { $eq: ["$_id", "$$uid"] } } }
      ],
      as: "user"
    }
  }
])

📊 监控和诊断

// 查看服务器状态
db.serverStatus()

// 查看数据库统计
db.stats()

// 查看连接信息
db.currentOp()

// 查看慢操作
db.currentOp({ "active": true, "secs_running": { "$gt": 5 } })

// 终止操作
db.killOp(opid)

// 查看集合统计
db.users.stats()

// 查看索引使用情况
db.users.aggregate([{ $indexStats: {} }])

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

// 查看分片统计
sh.status(true)

🏗️ 实战案例

🛒 电商数据建模

// 用户文档(内嵌地址)
db.users.insertOne({
  _id: ObjectId("..."),
  username: "john",
  email: "john@example.com",
  addresses: [
    { type: "home", street: "123 Main St", city: "NY" },
    { type: "work", street: "456 Office Ave", city: "NY" }
  ],
  created_at: ISODate()
})

// 商品文档(内嵌变体)
db.products.insertOne({
  _id: ObjectId("..."),
  name: "iPhone 14",
  description: "Latest iPhone",
  sku: "IPHONE-14-128GB",
  variants: [
    { size: "128GB", color: "black", price: 999, stock: 50 },
    { size: "256GB", color: "blue", price: 1199, stock: 30 }
  ],
  category_ids: [ObjectId("cat1"), ObjectId("cat2")],
  created_at: ISODate()
})

// 订单文档(混合建模:关键数据内嵌)
db.orders.insertOne({
  _id: ObjectId("..."),
  user_id: ObjectId("..."),
  items: [
    { product_id: ObjectId("..."), quantity: 2, price: 999 },
    { product_id: ObjectId("..."), quantity: 1, price: 199 }
  ],
  total: 2197,
  status: "pending",
  shipping: {
    name: "John Doe",
    address: { street: "123 Main St", city: "NY" }
  },
  created_at: ISODate(),
  updated_at: ISODate()
})

📊 销售分析聚合

// 按日期统计销售额
db.orders.aggregate([
  { $match: { status: "completed" } },
  {
    $group: {
      _id: {
        $dateToString: { format: "%Y-%m-%d", date: "$created_at" }
      },
      totalSales: { $sum: "$total" },
      orderCount: { $sum: 1 },
      avgOrderValue: { $avg: "$total" }
    }
  },
  { $sort: { _id: 1 } }
])

// 热销商品Top10
db.orders.aggregate([
  { $unwind: "$items" },
  {
    $group: {
      _id: "$items.product_id",
      totalQuantity: { $sum: "$items.quantity" },
      totalRevenue: { $sum: { $multiply: ["$items.quantity", "$items.price"] } }
    }
  },
  { $sort: { totalQuantity: -1 } },
  { $limit: 10 },
  {
    $lookup: {
      from: "products",
      localField: "_id",
      foreignField: "_id",
      as: "product"
    }
  },
  { $unwind: "$product" },
  {
    $project: {
      productName: "$product.name",
      totalSold: "$totalQuantity",
      revenue: "$totalRevenue"
    }
  }
])

// 用户购买行为分析
db.orders.aggregate([
  {
    $group: {
      _id: "$user_id",
      totalOrders: { $sum: 1 },
      totalSpent: { $sum: "$total" },
      avgOrderValue: { $avg: "$total" },
      firstPurchase: { $min: "$created_at" },
      lastPurchase: { $max: "$created_at" }
    }
  },
  { $match: { totalOrders: { $gte: 5 } } },
  { $sort: { totalSpent: -1 } },
  { $limit: 100 }
])

🔍 全文搜索实现

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

// 文本搜索查询
db.articles.find({ $text: { $search: "mongodb tutorial" } })

// 加权搜索
db.articles.find(
  { $text: { $search: "mongodb tutorial" } },
  { score: { $meta: "textScore" } }
).sort({ score: { $meta: "textScore" } })

// 复杂搜索(结合其他条件)
db.articles.find({
  $text: { $search: "mongodb" },
  tags: "database",
  published: true,
  views: { $gte: 100 }
})

// Atlas Search(MongoDB云服务)
// 在Atlas中创建搜索索引
{
  "mappings": {
    "dynamic": false,
    "fields": {
      "title": { "type": "string" },
      "content": { "type": "string" }
    }
  }
}

db.articles.aggregate([
  {
    $search: {
      text: {
        query: "mongodb",
        path: ["title", "content"]
      }
    }
  }
])

📋 MongoDB 最佳实践总结

✅ 建模原则

  • • 经常一起查询的数据内嵌
  • • 需要独立访问的数据引用
  • • 避免无界数组和超长嵌套
  • • 预分配文档ID
  • • 使用合适的数据类型
  • • 考虑读写比例

⚡ 性能优化

  • • 为查询字段创建索引
  • • 使用复合索引优化多字段查询
  • • 限制查询返回的字段数量
  • • 使用批量操作减少网络往返
  • • 合理配置连接池大小
  • • 监控慢查询和热点

🔒 安全措施

  • • 启用认证和授权
  • • 使用TLS/SSL加密传输
  • • 实施最小权限原则
  • • 定期备份和测试恢复
  • • 审计和监控敏感操作
  • • 保持MongoDB版本更新

📊 运维监控

  • • 监控复制延迟
  • • 跟踪Oplog大小
  • • 定期检查索引使用情况
  • • 监控分片分布平衡
  • • 建立告警机制
  • • 制定灾难恢复计划
← 返回数据库首页