Skip to content

MongoDB 数据库

欢迎来到 MongoDB 数据库知识库!

🍃 MongoDB 简介

MongoDB 是最流行的 NoSQL 文档数据库,以 JSON 格式存储数据。它提供了灵活的模式、强大的查询能力和横向扩展性,特别适合处理非结构化和半结构化数据。

🎯 MongoDB vs 关系型数据库

概念MongoDBMySQL/PostgreSQL
数据单位Document (文档)Row (行)
集合CollectionTable (表)
数据库DatabaseDatabase
Schema灵活,动态固定,需预定义
关系嵌入或引用外键关联
扩展横向扩展(分片)纵向扩展为主

🎯 适用场景

✅ 特别适合

  • 快速迭代 - Schema 灵活,无需迁移
  • 半结构化数据 - JSON 格式数据
  • 大数据量 - 分片集群支持
  • 实时分析 - 聚合管道
  • 内容管理 - CMS、博客
  • 物联网 - 日志、传感器数据
  • 移动应用 - 用户配置、社交数据

⚠️ 不太适合

  • 复杂事务(虽然支持多文档事务)
  • 复杂的多表关联
  • 需要强一致性的场景

🎯 学习路线

第一阶段:MongoDB 基础 (1-2周)

  1. 基本概念

    • 文档、集合、数据库
    • BSON 格式
    • ObjectId
  2. CRUD 操作

    • 插入文档
    • 查询文档
    • 更新文档
    • 删除文档

第二阶段:高级查询 (2-3周)

  1. 查询操作符

    • 比较操作符
    • 逻辑操作符
    • 数组操作符
  2. 聚合管道

    • $match、$project
    • $group、$sort
    • $lookup 关联

第三阶段:索引与优化 (1-2周)

  1. 索引

    • 单字段索引
    • 复合索引
    • 文本索引
    • 地理空间索引
  2. 性能优化

    • explain() 分析
    • 索引优化
    • 查询优化

第四阶段:高可用与分片 (持续)

  1. 副本集

    • 主从复制
    • 自动故障转移
  2. 分片集群

    • 水平扩展
    • 分片键选择

✨ MongoDB 特点

✅ 核心优势

  • 灵活的文档模型 - JSON 格式,动态 Schema
  • 强大的查询 - 丰富的查询操作符
  • 聚合框架 - 数据处理和分析
  • 水平扩展 - 自动分片
  • 高可用 - 副本集自动故障转移
  • 索引支持 - 多种索引类型
  • 原子操作 - 文档级别的原子性

🔧 数据类型

  • String(字符串)
  • Number(数字)
  • Boolean(布尔)
  • Date(日期)
  • Array(数组)
  • Object(嵌入文档)
  • ObjectId(文档ID)
  • Binary Data(二进制)
  • Null

📖 CRUD 操作

插入文档

javascript
// 插入单个文档
db.users.insertOne({
    username: "张三",
    email: "zhang@example.com",
    age: 25,
    tags: ["JavaScript", "MongoDB"],
    address: {
        city: "北京",
        district: "朝阳区"
    },
    createdAt: new Date()
});

// 插入多个文档
db.users.insertMany([
    { username: "李四", age: 30 },
    { username: "王五", age: 28 }
]);

查询文档

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

// 条件查询
db.users.find({ age: { $gt: 25 } });

// 查询单个
db.users.findOne({ username: "张三" });

// 指定返回字段
db.users.find({}, { username: 1, email: 1, _id: 0 });

// 排序和限制
db.users.find().sort({ age: -1 }).limit(10);

// 数组查询
db.users.find({ tags: "JavaScript" });
db.users.find({ tags: { $all: ["JavaScript", "MongoDB"] } });

// 嵌入文档查询
db.users.find({ "address.city": "北京" });

更新文档

javascript
// 更新单个文档
db.users.updateOne(
    { username: "张三" },
    { $set: { age: 26 } }
);

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

// 替换文档
db.users.replaceOne(
    { username: "张三" },
    { username: "张三", age: 26, email: "new@example.com" }
);

// 数组操作
db.users.updateOne(
    { username: "张三" },
    { $push: { tags: "Node.js" } }
);

db.users.updateOne(
    { username: "张三" },
    { $pull: { tags: "JavaScript" } }
);

删除文档

javascript
// 删除单个文档
db.users.deleteOne({ username: "张三" });

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

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

🔍 查询操作符

比较操作符

javascript
// $eq, $ne, $gt, $gte, $lt, $lte
db.users.find({ age: { $gte: 18, $lte: 30 } });

// $in, $nin
db.users.find({ status: { $in: ["active", "pending"] } });

逻辑操作符

javascript
// $and
db.users.find({ 
    $and: [
        { age: { $gte: 18 } },
        { status: "active" }
    ]
});

// $or
db.users.find({ 
    $or: [
        { age: { $lt: 18 } },
        { age: { $gt: 60 } }
    ]
});

// $not
db.users.find({ age: { $not: { $gte: 18 } } });

元素操作符

javascript
// $exists - 字段是否存在
db.users.find({ email: { $exists: true } });

// $type - 字段类型
db.users.find({ age: { $type: "number" } });

📊 聚合管道

javascript
// 统计每个城市的用户数量
db.users.aggregate([
    {
        $group: {
            _id: "$address.city",
            count: { $sum: 1 },
            avgAge: { $avg: "$age" }
        }
    },
    {
        $sort: { count: -1 }
    }
]);

// 多阶段聚合
db.orders.aggregate([
    // 过滤
    { $match: { status: "completed" } },
    
    // 关联用户表
    {
        $lookup: {
            from: "users",
            localField: "userId",
            foreignField: "_id",
            as: "user"
        }
    },
    
    // 展开数组
    { $unwind: "$user" },
    
    // 投影
    {
        $project: {
            orderNo: 1,
            amount: 1,
            "user.username": 1
        }
    },
    
    // 排序
    { $sort: { amount: -1 } },
    
    // 限制
    { $limit: 10 }
]);

🔍 索引

创建索引

javascript
// 单字段索引
db.users.createIndex({ username: 1 });  // 1: 升序, -1: 降序

// 复合索引
db.users.createIndex({ age: 1, username: 1 });

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

// 文本索引(全文搜索)
db.articles.createIndex({ content: "text" });

// 部分索引
db.users.createIndex(
    { email: 1 },
    { partialFilterExpression: { age: { $gte: 18 } } }
);

// TTL 索引(自动过期)
db.sessions.createIndex(
    { createdAt: 1 },
    { expireAfterSeconds: 3600 }
);

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

// 删除索引
db.users.dropIndex("username_1");

索引优化

javascript
// 查询计划分析
db.users.find({ age: { $gt: 25 } }).explain("executionStats");

// 关注指标:
// - executionTimeMillis: 执行时间
// - totalDocsExamined: 扫描文档数
// - totalKeysExamined: 扫描索引数
// - stage: IXSCAN(索引扫描)vs COLLSCAN(全集合扫描)

🚀 副本集

         Primary
         (主节点)
         /      \
   写入 /        \ 同步
       /          \
  Secondary    Secondary
  (从节点)     (从节点)
      \          /
   读取 \        / 读取

特点

  • 自动故障转移 - 主节点故障时自动选举
  • 读写分离 - 主节点写,从节点读
  • 数据冗余 - 多个副本保证数据安全

🔀 分片集群

       Client
          |
       mongos (路由)
          |
    ---------------
    |      |      |
  Shard1 Shard2 Shard3

特点

  • 水平扩展 - 数据分布在多个分片
  • 自动均衡 - 数据自动迁移
  • 分片键 - 决定数据如何分片

💡 最佳实践

  1. 文档设计

    • 根据查询模式设计
    • 合理使用嵌入 vs 引用
    • 避免过大的文档(<16MB)
    • 使用有意义的字段名
  2. 索引策略

    • 为高频查询创建索引
    • 复合索引字段顺序很重要
    • 定期检查索引使用情况
    • 删除未使用的索引
  3. 查询优化

    • 使用投影减少数据传输
    • 使用 explain() 分析查询
    • 避免全集合扫描
    • 合理使用聚合管道
  4. 数据建模

    • 一对一:嵌入
    • 一对多(少):嵌入
    • 一对多(多):引用
    • 多对多:引用 + 中间集合

📖 学习资源

官方资源

推荐书籍

  • 《MongoDB 权威指南》
  • 《MongoDB 实战》
  • 《深入学习 MongoDB》

工具推荐

  • MongoDB Compass - 官方 GUI 工具
  • Studio 3T - 功能强大的客户端
  • mongostat - 性能监控
  • mongotop - 实时统计

准备好了吗?开始你的 MongoDB 学习之旅!