《 MongoDB 教程 》—— 不可多得的 MongoDB

MongoDB 从入门到实战全教程

MongoDB 是目前最主流的非关系型(NoSQL)数据库之一,以「文档型存储、高可用、易扩展」为核心特点,广泛应用于互联网、大数据、微服务等场景。本教程从环境搭建到高级实战,覆盖 MongoDB 核心语法、索引优化、集群部署等内容,适合零基础入门,也可作为开发参考手册。

一、MongoDB 核心概念(必懂)

1.1 为什么选择 MongoDB?

传统关系型数据库(MySQL/PostgreSQL)基于「表 - 行 - 列」存储,适合结构化数据,但面对高频读写、海量数据、灵活字段的场景(如社交 APP 动态、电商订单、日志存储),存在扩展难、改表成本高的问题。

MongoDB 作为文档型数据库,核心优势:

  • 灵活的文档模型:无需预定义表结构,字段可动态扩展;
  • 高性能:支持内存映射、索引优化,读写速度快;
  • 易扩展:原生支持分片集群,可横向扩展;
  • 高可用:副本集机制保证数据不丢失;
  • 支持复杂查询:内置丰富的查询语法、聚合管道,满足业务需求。

1.2 核心概念对比(与 MySQL)

MongoDB 没有「表、行、列、主键、外键」等概念,对应关系如下:

MySQL 概念 MongoDB 概念 说明
数据库(Database) 数据库(Database) 逻辑隔离的存储单元,一个 MongoDB 实例可包含多个数据库
表(Table) 集合(Collection) 存储文档的容器,相当于 MySQL 的表,无需定义结构
行(Row) 文档(Document) 最小数据单元,以 BSON(二进制 JSON)格式存储,字段键值对形式
列(Column) 字段(Field) 文档中的键值对,字段类型灵活(字符串、数字、数组、嵌套文档等)
主键(Primary Key) _id 字段 每个文档默认的唯一标识,MongoDB 自动生成,也可自定义
索引(Index) 索引(Index) 加速查询,支持单字段、复合、地理空间、文本等多种索引类型
外键(Foreign Key) 无原生支持 可通过应用层或聚合管道实现关联查询

1.3 BSON 数据类型

MongoDB 以 BSON 存储数据,支持比 JSON 更丰富的类型,核心类型:

类型 说明 示例
String 字符串,UTF-8 编码 "name": "张三"
Number 数字(int32/int64/double) "age": 20, "score": 98.5
Boolean 布尔值 "is_vip": true
Array 数组,可包含任意类型 "hobbies": ["篮球", "编程"]
Object 嵌套文档 "address": {"city": "北京"}
ObjectId 唯一标识,默认 _id 类型 "_id": ObjectId("65ed...")
Date 日期时间 "create_time": ISODate("2026-02-08T00:00:00Z")
Null 空值 "remark": null
Binary Data 二进制数据(存储文件、图片等) -

二、环境搭建

2.1 系统要求

  • 操作系统:Windows 10+/Mac OS 10.15+/Linux(CentOS 7+/Ubuntu 18.04+);
  • 内存:建议 2GB 以上;
  • 权限:Mac/Linux 需要管理员权限(sudo)。

2.2 安装 MongoDB(以社区版为例)

方式 1:官网下载安装包(推荐新手)

  1. 访问 MongoDB 官网下载页

  2. 选择对应系统版本,下载后安装:

    • Windows:双击安装包,勾选「Complete」,取消「Install MongoDB Compass」(可视化工具可单独装);

    • Mac:解压后将 mongodb/bin 加入系统环境变量;

    • Linux: # CentOS 安装示例 sudo yum install -y mongodb-org # Ubuntu 安装示例 sudo apt-get install -y mongodb-org

方式 2:包管理器安装(Mac/Linux)

bash 复制代码
# Mac(Homebrew)
brew tap mongodb/brew
brew install mongodb-community@7.0

# Linux(Ubuntu)
wget -qO - https://www.mongodb.org/static/pgp/server-7.0.asc | sudo apt-key add -
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/7.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list
sudo apt-get update
sudo apt-get install -y mongodb-org

2.3 配置环境变量(关键)

确保 mongod(服务端)和 mongo/mongosh(客户端)命令可全局执行:

  • Windows:将 MongoDB\Server\7.0\bin 加入系统「环境变量 - Path」;

  • Mac/Linux:编辑 ~/.bashrc~/.zshrc,添加: export PATH=/usr/local/mongodb/bin:$PATH source ~/.zshrc # 生效配置

2.4 启动 MongoDB 服务

步骤 1:创建数据存储目录

MongoDB 默认数据存储路径为 /data/db(Mac/Linux)或 C:\data\db(Windows),需手动创建:

bash 复制代码
# Mac/Linux
sudo mkdir -p /data/db
sudo chmod 777 /data/db # 赋予读写权限

# Windows(管理员命令行)
md C:\data\db

步骤 2:启动服务

perl 复制代码
# 前台启动(测试用,关闭终端则服务停止)
mongod

# 后台启动(生产环境)
# Mac/Linux
sudo mongod --fork --logpath /var/log/mongodb/mongod.log

# Windows 服务启动
net start MongoDB

步骤 3:连接 MongoDB

shell 复制代码
# 新版用 mongosh(推荐)
mongosh

# 旧版用 mongo
mongo

# 成功连接会显示:MongoDB shell version v7.0.0
# 提示符变为:test>(test 是默认数据库)

2.5 可视化工具(可选)

新手推荐使用 MongoDB Compass(官方免费),下载地址:MongoDB Compass,支持可视化操作数据库、执行查询、查看索引等。

三、基础操作(数据库 / 集合 / 文档)

3.1 数据库操作

3.1.1 查看所有数据库

bash 复制代码
show dbs # 显示有数据的数据库(空数据库不显示)

3.1.2 切换 / 创建数据库

perl 复制代码
use test_db # 切换到 test_db,若不存在则创建(需插入数据后才会显示)

3.1.3 删除数据库

perl 复制代码
use test_db # 先切换到目标数据库
db.dropDatabase() # 删除当前数据库

3.2 集合操作

集合相当于 MySQL 的表,无需提前定义结构。

3.2.1 创建集合(可选)

yaml 复制代码
# 方式 1:直接插入文档,自动创建集合
db.user.insertOne({ name: "张三", age: 20 }) # 自动创建 user 集合

# 方式 2:手动创建(可指定配置,如大小、索引)
db.createCollection("product", {
  capped: true, # 固定大小集合
  size: 1024 * 1024, # 大小 1MB
  max: 1000 # 最多存储 1000 个文档
})

3.2.2 查看所有集合

sql 复制代码
show collections # 或 show tables

3.2.3 删除集合

bash 复制代码
db.user.drop() # 删除 user 集合

3.3 文档操作(核心)

文档是 MongoDB 最小数据单元,以下以 user 集合为例,讲解增删改查。

3.3.1 插入文档

插入单个文档(insertOne)
php 复制代码
db.user.insertOne({
  name: "张三",
  age: 20,
  gender: "男",
  hobbies: ["篮球", "编程"],
  address: {
    city: "北京",
    district: "朝阳区"
  },
  create_time: new Date()
})

返回结果:

json

json 复制代码
{
  "acknowledged": true,
  "insertedId": ObjectId("65ed8b0f1234567890abcdef") // 自动生成的 _id
}
插入多个文档(insertMany)
php 复制代码
db.user.insertMany([
  { name: "李四", age: 22, gender: "女", hobbies: ["读书", "旅游"] },
  { name: "王五", age: 25, gender: "男", hobbies: ["游戏", "音乐"] },
  { name: "赵六", age: 18, gender: "男", hobbies: ["运动", "摄影"] }
])

3.3.2 查询文档

查询所有文档(find)
scss 复制代码
db.user.find() # 返回所有文档(默认显示 20 条,输入 it 查看下一页)
db.user.find().pretty() # 格式化输出,更易读
条件查询(等于 / 大于 / 小于)
php 复制代码
# 1. 等于:查询性别为男的文档
db.user.find({ gender: "男" }).pretty()

# 2. 大于:查询年龄大于 20 的文档
db.user.find({ age: { $gt: 20 } }).pretty()

# 3. 小于等于:查询年龄小于等于 18 的文档
db.user.find({ age: { $lte: 18 } }).pretty()

# 4. 多条件(且):年龄>20 且性别为女
db.user.find({ age: { $gt: 20 }, gender: "女" }).pretty()

# 5. 多条件(或):年龄<20 或性别为男
db.user.find({ $or: [{ age: { $lt: 20 } }, { gender: "男" }] }).pretty()
字段过滤(只返回指定字段)
php 复制代码
# 查询所有文档,只返回 name 和 age 字段(_id 默认为 1,需手动设为 0)
db.user.find({}, { name: 1, age: 1, _id: 0 }).pretty()

# 排除指定字段(返回除 hobbies 外的所有字段)
db.user.find({}, { hobbies: 0 }).pretty()
排序(sort)
scss 复制代码
# 按年龄升序(1 升序,-1 降序)
db.user.find().sort({ age: 1 }).pretty()

# 多字段排序:按年龄降序,姓名升序
db.user.find().sort({ age: -1, name: 1 }).pretty()
分页(skip + limit)
scss 复制代码
# 跳过前 1 条,取 2 条(第 2-3 条)
db.user.find().skip(1).limit(2).pretty()
统计数量(countDocuments)
php 复制代码
# 统计所有文档数量
db.user.countDocuments()

# 统计条件文档数量:年龄>20 的文档数
db.user.countDocuments({ age: { $gt: 20 } })

3.3.3 更新文档

更新单个文档(updateOne)
php 复制代码
# 将张三的年龄改为 21
db.user.updateOne(
  { name: "张三" }, # 查询条件
  { $set: { age: 21 } } # 更新操作($set 表示设置字段)
)
更新多个文档(updateMany)
css 复制代码
# 将所有性别为男的文档,添加字段 is_adult: true
db.user.updateMany(
  { gender: "男" },
  { $set: { is_adult: true } }
)
替换文档(replaceOne)
php 复制代码
# 替换张三的整个文档(仅保留 _id)
db.user.replaceOne(
  { name: "张三" },
  { name: "张三", age: 21, gender: "男", job: "程序员" }
)

3.3.4 删除文档

删除单个文档(deleteOne)
php 复制代码
# 删除姓名为赵六的文档
db.user.deleteOne({ name: "赵六" })
删除多个文档(deleteMany)
php 复制代码
# 删除所有年龄<20 的文档
db.user.deleteMany({ age: { $lt: 20 } })
删除所有文档(保留集合)
bash 复制代码
db.user.deleteMany({}) # 清空集合,保留集合结构

四、高级查询(运算符 / 聚合 / 索引)

4.1 常用查询运算符

MongoDB 提供丰富的运算符,满足复杂查询需求,核心运算符分类:

4.1.1 比较运算符

运算符 说明 示例
$eq 等于 { age: { $eq: 20 } }
$ne 不等于 { age: { $ne: 20 } }
$gt 大于 { age: { $gt: 20 } }
$gte 大于等于 { age: { $gte: 20 } }
$lt 小于 { age: { $lt: 20 } }
$lte 小于等于 { age: { $lte: 20 } }
$in 包含在数组 { age: { $in: [20, 22, 25] } }
$nin 不包含 { age: { $nin: [20, 22] } }

4.1.2 逻辑运算符

运算符 说明 示例
$and { and: [{ age: { gt: 20 } }, {gender: "男"}] }
$or { or: [{ age: { lt: 20 } }, {gender: "女"}] }
$not { age: { not: { gt: 20 } } }(年龄 <=20)
$nor 都不满足 {$nor: [{ age: 20}, { gender: "男" }] }(年龄≠20 且性别≠男)

4.1.3 数组运算符

运算符 说明 示例
$all 包含数组所有元素 {hobbies: { $all: ["篮球", "编程"] } }
$size 数组长度等于 { hobbies: { $size: 2 } }
$elemMatch 数组元素匹配条件 { hobbies: { elemMatch: { eq: "篮球" } } }

4.1.4 示例:复杂查询

php 复制代码
# 查询:年龄在 20-25 之间,爱好包含篮球,地址城市为北京的男性用户
db.user.find({
  age: { $gte: 20, $lte: 25 },
  hobbies: { $all: ["篮球"] },
  "address.city": "北京", # 嵌套字段查询
  gender: "男"
}).pretty()

4.2 聚合管道(Aggregation Pipeline)

聚合管道是 MongoDB 高级查询核心,支持数据筛选、分组、排序、关联等操作,语法为 db.collection.aggregate([阶段1, 阶段2, ...])

4.2.1 核心聚合阶段

阶段 说明 示例
$match 筛选文档(类似 where) { match: { age: { gt: 20 } } }
$group 分组(类似 group by) { group: { _id: "gender", count: { $sum: 1 } } }
$sort 排序 { $sort: { age: -1 } }
$limit 限制结果数 { $limit: 10 }
$skip 跳过文档数 { $skip: 5 }
$project 字段过滤 / 重命名 { $project: { name: 1, age: 1, _id: 0 } }
$lookup 关联查询(类似 join) 关联 product 集合

4.2.2 聚合示例

示例 1:分组统计
bash 复制代码
# 按性别分组,统计每组人数、平均年龄
db.user.aggregate([
  { $match: { age: { $gt: 18 } } }, # 先筛选成年用户
  {
    $group: {
      _id: "$gender", # 分组字段(_id 是固定关键字)
      total: { $sum: 1 }, # 统计数量
      avg_age: { $avg: "$age" } # 计算平均年龄
    }
  },
  { $sort: { total: -1 } } # 按人数降序
])
示例 2:关联查询

假设有 order 集合(订单)和 user 集合(用户),关联查询用户及其订单:

php 复制代码
# 先插入订单数据
db.order.insertMany([
  { user_id: ObjectId("65ed8b0f1234567890abcdef"), product: "手机", price: 2999 },
  { user_id: ObjectId("65ed8b0f1234567890abcdef"), product: "耳机", price: 199 }
])

# 关联查询:获取用户信息 + 订单列表
db.user.aggregate([
  {
    $lookup: {
      from: "order", # 关联的集合
      localField: "_id", # 当前集合的关联字段
      foreignField: "user_id", # 关联集合的字段
      as: "orders" # 关联结果的字段名
    }
  },
  { $project: { name: 1, age: 1, orders: 1, _id: 0 } } # 只显示指定字段
])

4.3 索引(性能优化核心)

索引能大幅提升查询效率,MongoDB 支持多种索引类型,核心原理与 MySQL 类似(B 树索引)。

4.3.1 查看索引

bash 复制代码
db.user.getIndexes() # 查看 user 集合的所有索引(默认有 _id 索引)

4.3.2 创建索引

单字段索引
php 复制代码
# 为 age 字段创建升序索引(1 升序,-1 降序)
db.user.createIndex({ age: 1 })
复合索引
php 复制代码
# 为 gender 和 age 创建复合索引(先按 gender 排序,再按 age 排序)
db.user.createIndex({ gender: 1, age: -1 })
唯一索引
php 复制代码
# 为 name 字段创建唯一索引(不允许重复)
db.user.createIndex({ name: 1 }, { unique: true })
文本索引(支持全文搜索)
php 复制代码
# 为 name 和 hobbies 字段创建文本索引
db.user.createIndex({ name: "text", hobbies: "text" })

# 使用文本索引查询:包含「篮球」的文档
db.user.find({ $text: { $search: "篮球" } })

4.3.3 删除索引

scss 复制代码
# 删除指定索引(索引名可通过 getIndexes() 获取)
db.user.dropIndex("age_1")

# 删除所有索引(保留 _id 索引)
db.user.dropIndexes()

4.3.4 索引使用建议

  1. 优先为查询条件、排序字段创建索引;

  2. 复合索引遵循「最左前缀原则」(查询条件需包含索引第一个字段);

  3. 避免创建过多索引(会降低插入 / 更新速度);

  4. explain() 分析查询是否使用索引: db.user.find({ age: { $gt: 20 } }).explain("executionStats") # 查看 executionStats -> executionStages -> stage: # IXSCAN 表示使用索引,COLLSCAN 表示全表扫描(未使用索引)

五、数据备份与恢复

5.1 备份(mongodump)

bash 复制代码
# 备份所有数据库
mongodump --out /data/backup/mongodb/20260208

# 备份指定数据库
mongodump --db test_db --out /data/backup/mongodb/20260208

# 备份指定集合
mongodump --db test_db --collection user --out /data/backup/mongodb/20260208

5.2 恢复(mongorestore)

bash 复制代码
# 恢复所有数据库
mongorestore /data/backup/mongodb/20260208

# 恢复指定数据库
mongorestore --db test_db /data/backup/mongodb/20260208/test_db

# 恢复指定集合
mongorestore --db test_db --collection user /data/backup/mongodb/20260208/test_db/user.bson

六、集群部署(副本集 / 分片)

6.1 副本集(Replica Set)

副本集是 MongoDB 高可用核心,由一个主节点(Primary)、多个从节点(Secondary)和可选的仲裁节点(Arbiter)组成,主节点负责读写,从节点同步数据,主节点故障时自动切换。

6.1.1 搭建副本集(3 节点示例)

css 复制代码
# 1. 创建数据目录
mkdir -p /data/mongodb/{node1,node2,node3}

# 2. 启动 3 个节点
mongod --port 27017 --dbpath /data/mongodb/node1 --replSet rs0 --fork --logpath /var/log/mongodb/node1.log
mongod --port 27018 --dbpath /data/mongodb/node2 --replSet rs0 --fork --logpath /var/log/mongodb/node2.log
mongod --port 27019 --dbpath /data/mongodb/node3 --replSet rs0 --fork --logpath /var/log/mongodb/node3.log

# 3. 初始化副本集
mongosh --port 27017
rs.initiate({
  _id: "rs0",
  members: [
    { _id: 0, host: "localhost:27017" },
    { _id: 1, host: "localhost:27018" },
    { _id: 2, host: "localhost:27019" }
  ]
})

# 4. 查看副本集状态
rs.status()

6.2 分片集群(Sharding)

分片集群用于海量数据存储,将数据分散到多个分片(Shard)节点,实现水平扩展,核心组件:

  • 分片(Shard):存储数据的节点(通常是副本集);
  • 配置服务器(Config Server):存储集群元数据;
  • 路由服务器(Mongos):接收客户端请求,路由到对应分片。

6.2.1 分片集群搭建(简化版)

css 复制代码
# 1. 启动配置服务器
mongod --port 27019 --dbpath /data/mongodb/config --configsvr --replSet configRS --fork --logpath /var/log/mongodb/config.log

# 2. 启动分片节点
mongod --port 27020 --dbpath /data/mongodb/shard1 --shardsvr --replSet shard1RS --fork --logpath /var/log/mongodb/shard1.log
mongod --port 27021 --dbpath /data/mongodb/shard2 --shardsvr --replSet shard2RS --fork --logpath /var/log/mongodb/shard2.log

# 3. 启动路由服务器
mongos --port 27017 --configdb configRS/localhost:27019 --fork --logpath /var/log/mongodb/mongos.log

# 4. 添加分片到集群
mongosh --port 27017
sh.addShard("shard1RS/localhost:27020")
sh.addShard("shard2RS/localhost:27021")

# 5. 启用数据库分片
sh.enableSharding("test_db")

# 6. 为集合指定分片键
sh.shardCollection("test_db.user", { "age": 1 })

七、Node.js 操作 MongoDB(实战)

7.1 安装依赖

bash 复制代码
npm install mongoose # MongoDB ODM(对象文档映射),简化操作

7.2 连接 MongoDB

javascript 复制代码
const mongoose = require('mongoose');

// 连接本地 MongoDB
mongoose.connect('mongodb://localhost:27017/test_db')
  .then(() => console.log('MongoDB 连接成功'))
  .catch(err => console.error('连接失败:', err));

// 连接副本集
// mongoose.connect('mongodb://localhost:27017,localhost:27018,localhost:27019/test_db?replicaSet=rs0');

7.3 定义 Schema 和 Model

php 复制代码
// 定义用户 Schema(相当于表结构)
const userSchema = new mongoose.Schema({
  name: { type: String, required: true }, // 必传
  age: { type: Number, min: 0, max: 120 }, // 数值范围
  gender: { type: String, enum: ["男", "女"] }, // 枚举值
  hobbies: [String], // 字符串数组
  address: {
    city: String,
    district: String
  },
  create_time: { type: Date, default: Date.now } // 默认值
});

// 创建 Model(对应 user 集合)
const User = mongoose.model('User', userSchema);

7.4 增删改查示例

javascript 复制代码
// 1. 新增用户
async function createUser() {
  const user = new User({
    name: "张三",
    age: 20,
    gender: "男",
    hobbies: ["篮球", "编程"],
    address: { city: "北京", district: "朝阳区" }
  });
  await user.save();
  console.log('用户创建成功:', user);
}

// 2. 查询用户
async function findUsers() {
  // 查询所有男性用户
  const users = await User.find({ gender: "男" });
  console.log('查询结果:', users);

  // 分页查询:第 2 页,每页 10 条
  const pageUsers = await User.find()
    .skip(10)
    .limit(10)
    .sort({ age: -1 });
}

// 3. 更新用户
async function updateUser() {
  await User.updateOne({ name: "张三" }, { $set: { age: 21 } });
  console.log('更新成功');
}

// 4. 删除用户
async function deleteUser() {
  await User.deleteOne({ name: "张三" });
  console.log('删除成功');
}

// 执行函数
createUser();

八、常见问题与优化

8.1 性能优化

  1. 合理创建索引:避免全表扫描;
  2. 限制返回字段:只查询需要的字段,减少数据传输;
  3. 批量操作:用 insertMany/updateMany 替代循环单条操作;
  4. 避免大文档:单个文档建议小于 16MB;
  5. 启用读写分离:副本集从节点只读,分担主节点压力。

8.2 常见错误

  1. connect ECONNREFUSED:MongoDB 服务未启动,或端口错误;
  2. duplicate key error:唯一索引字段重复;
  3. BSONObjTooLarge:文档超过 16MB 限制;
  4. CursorNotFound:游标超时,需缩短查询时间或增加游标超时时间。

8.3 安全建议

  1. 设置访问权限:为数据库创建用户,禁止匿名访问; use admin db.createUser({ user: "admin", pwd: "123456", roles: [{ role: "root", db: "admin" }] })

  2. 启用认证:启动 MongoDB 时添加 --auth 参数;

  3. 限制 IP 访问:仅允许业务服务器访问 MongoDB 端口;

  4. 加密传输:启用 SSL/TLS,避免数据明文传输。

九、总结

MongoDB 作为文档型数据库,核心优势是「灵活、高性能、易扩展」,适合以下场景:

  • 高频读写的互联网应用(如社交、电商);
  • 海量日志 / 埋点数据存储;
  • 微服务架构下的独立数据存储;
  • 需快速迭代、字段灵活的业务。

本教程覆盖 MongoDB 从环境搭建到集群部署的全流程,核心要点:

  1. 核心概念:数据库→集合→文档,BSON 数据类型;
  2. 基础操作:增删改查(insert/find/update/delete);
  3. 高级特性:聚合管道、索引、副本集 / 分片;
  4. 实战:Node.js + Mongoose 操作 MongoDB;
  5. 优化:索引优化、性能调优、安全配置。
相关推荐
Wiittch8 小时前
HashMap源码深度剖析
后端
攀登的牵牛花8 小时前
前端向架构突围系列 - 状态数据设计 [8 - 3]:服务端状态与客户端状态的架构分离
前端
若水不如远方8 小时前
分布式一致性(三):共识的黎明——Quorum 机制与 Basic Paxos
分布式·后端·算法
三千星8 小时前
从Java到AI:我的转型之路 Ⅱ —— 手撸一个DeepSeek工具库
后端
beata8 小时前
Java基础-9:深入 Java 虚拟机(JVM):从底层源码到核心原理的全面解析
java·后端
掘金安东尼8 小时前
⏰前端周刊第 452 期(2026年2月2日-2月8日)
前端·javascript·github
古茗前端团队8 小时前
业务方上压力了,前端仔速通RGB转CMYK
前端
SimonKing8 小时前
分享一款可以管理本地端口的IDEA插件:Port Manager
java·后端·程序员
广州华水科技8 小时前
单北斗变形监测一体机在基础设施安全与地质灾害监测中的应用价值分析
前端