前言

MongoDB是当今最流行的NoSQL数据库之一,它以文档存储模型、高性能和易扩展性著称。作为传统关系型数据库的重要补充,MongoDB在处理非结构化数据、快速开发和大规模分布式应用方面展现出独特优势。本文将全面介绍MongoDB的核心概念、操作方法、高级特性以及实际应用场景。

一、MongoDB基础概念

(一)什么是MongoDB

MongoDB是一个基于分布式文件存储的NoSQL数据库,由C++语言编写。它采用文档存储模型,将数据存储为类似JSON的BSON(Binary JSON)格式,具有高性能、高可用性和易扩展的特点。

MongoDB的核心特点:

  • 文档导向:数据以文档形式存储,支持复杂的数据结构
  • 动态模式:无需预定义表结构,支持灵活的数据模型
  • 水平扩展:原生支持分片(Sharding)和副本集(Replica Set)
  • 丰富查询:支持复杂查询、索引和聚合操作
  • 高性能:内存映射文件和高效的存储引擎

(二)核心概念详解

1. 文档(Document)

文档是MongoDB的基本数据单元,具有以下特点:

  • BSON格式:类似JSON但支持更多数据类型(如ObjectId、Date等)
  • 嵌套结构:支持嵌套文档和数组,可以表示复杂的数据关系
  • 动态模式:同一集合中的文档可以有不同的字段结构
  • 最大大小:单个文档最大16MB

2. 集合(Collection)

集合是文档的容器,类似于关系型数据库中的表:

  • 无模式约束:不需要预定义字段结构
  • 灵活存储:可以存储不同结构的文档
  • 自动创建:首次插入文档时自动创建集合
  • 命名规范:集合名不能包含某些特殊字符

3. 数据库(Database)

数据库是集合的容器:

  • 多数据库支持:一个MongoDB实例可以包含多个数据库
  • 独立命名空间:每个数据库有独立的文件和权限
  • 默认数据库:test、admin、local、config等系统数据库

4. MongoDB vs 关系型数据库对比

MongoDB 关系型数据库 说明
Database Database 数据库
Collection Table 表/集合
Document Row 行/文档
Field Column 列/字段
Index Index 索引
Embedded Document JOIN 关联关系

(三)数据模型示例

1. 用户文档结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 用户文档示例:展示MongoDB文档的灵活性和嵌套能力
{
"_id": ObjectId("507f1f77bcf86cd799439011"), // MongoDB自动生成的唯一标识符
"username": "john_doe", // 用户名,字符串类型
"email": "john@example.com", // 邮箱地址,用于登录和通知
"profile": { // 嵌套文档:用户详细信息
"firstName": "John", // 名字
"lastName": "Doe", // 姓氏
"age": 30, // 年龄,数字类型
"avatar": "https://example.com/avatar.jpg", // 头像URL
"address": { // 嵌套文档:地址信息
"street": "123 Main St", // 街道地址
"city": "New York", // 城市
"state": "NY", // 州/省
"zipcode": "10001", // 邮政编码
"country": "USA" // 国家
}
},
"tags": ["developer", "mongodb", "nodejs"], // 数组:用户标签
"preferences": { // 嵌套文档:用户偏好设置
"language": "en", // 语言偏好
"timezone": "America/New_York", // 时区设置
"notifications": { // 通知设置
"email": true, // 邮件通知开关
"sms": false, // 短信通知开关
"push": true // 推送通知开关
}
},
"loginHistory": [ // 数组:登录历史记录
{
"timestamp": ISODate("2024-01-15T10:00:00Z"), // 登录时间
"ip": "192.168.1.100", // 登录IP
"device": "Chrome on Windows" // 设备信息
}
],
"status": "active", // 用户状态:active/inactive/suspended
"createdAt": ISODate("2024-01-15T10:00:00Z"), // 创建时间
"updatedAt": ISODate("2024-01-15T10:00:00Z") // 最后更新时间
}

2. 数据类型说明

MongoDB支持的主要数据类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// MongoDB数据类型示例
{
"string": "文本字符串", // String:UTF-8字符串
"number": 42, // Number:64位浮点数
"integer": NumberInt(32), // 32位整数
"long": NumberLong(64), // 64位整数
"boolean": true, // Boolean:布尔值
"date": ISODate("2024-01-15"), // Date:日期时间
"objectId": ObjectId("507f1f77bcf86cd799439011"), // ObjectId:唯一标识符
"array": [1, 2, 3], // Array:数组
"object": { "nested": "value" }, // Object:嵌套文档
"null": null, // Null:空值
"binary": BinData(0, "base64data"), // Binary:二进制数据
"regex": /pattern/i, // RegExp:正则表达式
"decimal": NumberDecimal("123.45") // Decimal128:高精度小数
}

二、MongoDB基本操作

(一)连接与环境配置

1. 连接数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 方法1:使用MongoDB Shell连接
// 连接到本地MongoDB实例的指定数据库
mongo mongodb://localhost:27017/mydb

// 方法2:使用连接字符串(包含认证信息)
mongo "mongodb://username:password@localhost:27017/mydb?authSource=admin"

// 方法3:使用Node.js驱动程序连接
const { MongoClient } = require('mongodb');

// 连接字符串配置
const uri = "mongodb://localhost:27017";
const client = new MongoClient(uri, {
useNewUrlParser: true, // 使用新的URL解析器
useUnifiedTopology: true // 使用新的服务器发现和监控引擎
});

// 异步连接示例
async function connectToMongoDB() {
try {
await client.connect(); // 建立连接
console.log("成功连接到MongoDB");

const database = client.db('mydb'); // 选择数据库
const collection = database.collection('users'); // 选择集合

// 执行数据库操作...

} catch (error) {
console.error("连接失败:", error);
} finally {
await client.close(); // 关闭连接
}
}

2. 连接字符串详解

1
2
3
4
5
6
7
8
9
10
11
12
// 完整的MongoDB连接字符串格式
// mongodb://[username:password@]host1[:port1][,...hostN[:portN]][/[defaultauthdb][?options]]

// 示例:生产环境连接字符串
const productionUri = "mongodb://admin:password@mongo1.example.com:27017,mongo2.example.com:27017,mongo3.example.com:27017/myapp?replicaSet=myReplicaSet&authSource=admin&ssl=true";

// 连接选项说明:
// - replicaSet: 副本集名称
// - authSource: 认证数据库
// - ssl: 启用SSL/TLS加密
// - maxPoolSize: 连接池最大连接数
// - retryWrites: 启用重试写入

(二)数据库操作

1. 数据库管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 创建/切换数据库(数据库在首次写入数据时才会真正创建)
use mydb // 切换到mydb数据库

// 查看所有数据库
show dbs // 显示所有数据库列表

// 查看当前使用的数据库
db // 显示当前数据库名称

// 获取数据库统计信息
db.stats() // 显示数据库大小、集合数量等统计信息

// 删除当前数据库(谨慎操作!)
db.dropDatabase() // 删除当前数据库及其所有集合

// 检查数据库是否存在
db.adminCommand("listDatabases").databases.forEach(
function(database) {
if (database.name === "mydb") {
print("数据库 mydb 存在");
}
}
);

2. 集合操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// 显式创建集合(可选,通常在插入数据时自动创建)
db.createCollection("users") // 创建名为users的集合

// 创建集合时指定选项
db.createCollection("logs", {
capped: true, // 创建固定大小集合
size: 100000, // 集合大小限制(字节)
max: 1000 // 文档数量限制
});

// 创建集合时设置验证规则
db.createCollection("products", {
validator: { // 文档验证器
$jsonSchema: {
bsonType: "object",
required: ["name", "price"], // 必需字段
properties: {
name: {
bsonType: "string",
description: "产品名称必须是字符串"
},
price: {
bsonType: "number",
minimum: 0,
description: "价格必须是非负数"
}
}
}
}
});

// 查看所有集合
show collections // 显示当前数据库中的所有集合

// 获取集合统计信息
db.users.stats() // 显示users集合的统计信息

// 重命名集合
db.users.renameCollection("customers") // 将users集合重命名为customers

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

// 检查集合是否存在
if (db.getCollectionNames().indexOf("users") !== -1) {
print("集合 users 存在");
}

文档操作(CRUD)

创建(Create)

1
2
3
4
5
6
7
8
9
10
11
12
13
// 插入单个文档
db.users.insertOne({
username: "alice",
email: "alice@example.com",
age: 25,
createdAt: new Date()
})

// 插入多个文档
db.users.insertMany([
{ username: "bob", email: "bob@example.com", age: 30 },
{ username: "charlie", email: "charlie@example.com", age: 35 }
])

读取(Read)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 查询所有文档
db.users.find()

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

// 投影查询(只返回指定字段)
db.users.find({}, { username: 1, email: 1 })

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

// 分页
db.users.find().skip(10).limit(5)

// 计数
db.users.countDocuments({ age: { $gte: 25 } })

更新(Update)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 更新单个文档
db.users.updateOne(
{ username: "alice" },
{ $set: { age: 26, updatedAt: new Date() } }
)

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

// 使用upsert(如果不存在则创建)
db.users.updateOne(
{ username: "david" },
{ $set: { email: "david@example.com", age: 28 } },
{ upsert: true }
)

删除(Delete)

1
2
3
4
5
// 删除单个文档
db.users.deleteOne({ username: "alice" })

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

查询操作符

比较操作符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 等于
db.users.find({ age: 25 })

// 不等于
db.users.find({ age: { $ne: 25 } })

// 大于
db.users.find({ age: { $gt: 25 } })

// 大于等于
db.users.find({ age: { $gte: 25 } })

// 小于
db.users.find({ age: { $lt: 25 } })

// 小于等于
db.users.find({ age: { $lte: 25 } })

// 在范围内
db.users.find({ age: { $in: [25, 30, 35] } })

// 不在范围内
db.users.find({ age: { $nin: [25, 30, 35] } })

逻辑操作符

1
2
3
4
5
6
7
8
9
10
11
12
13
// AND条件
db.users.find({ age: { $gte: 25 }, status: "active" })

// OR条件
db.users.find({
$or: [
{ age: { $lt: 25 } },
{ status: "premium" }
]
})

// NOT条件
db.users.find({ age: { $not: { $gt: 25 } } })

数组操作符

1
2
3
4
5
6
7
8
9
10
11
// 包含特定元素
db.users.find({ tags: "developer" })

// 包含所有指定元素
db.users.find({ tags: { $all: ["developer", "mongodb"] } })

// 数组大小
db.users.find({ tags: { $size: 3 } })

// 数组切片
db.users.find({ tags: { $slice: 2 } })

索引

创建索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 单字段索引
db.users.createIndex({ username: 1 })

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

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

// 文本索引
db.users.createIndex({ description: "text" })

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

索引类型

  • 单字段索引:单个字段的索引
  • 复合索引:多个字段的组合索引
  • 多键索引:数组字段的索引
  • 文本索引:全文搜索索引
  • 地理空间索引:地理位置数据索引

聚合管道

基本聚合

1
2
3
4
5
6
7
8
9
10
11
12
// 统计每个年龄段的用户数量
db.users.aggregate([
{
$group: {
_id: "$age",
count: { $sum: 1 }
}
},
{
$sort: { _id: 1 }
}
])

复杂聚合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 计算用户的平均订单金额
db.orders.aggregate([
{
$lookup: {
from: "users",
localField: "userId",
foreignField: "_id",
as: "user"
}
},
{
$unwind: "$user"
},
{
$group: {
_id: "$user.username",
avgOrderAmount: { $avg: "$amount" },
totalOrders: { $sum: 1 }
}
},
{
$sort: { avgOrderAmount: -1 }
}
])

数据验证

模式验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 创建带验证的集合
db.createCollection("users", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["username", "email"],
properties: {
username: {
bsonType: "string",
description: "必须是字符串"
},
email: {
bsonType: "string",
pattern: "^.+@.+$",
description: "必须是有效的邮箱格式"
},
age: {
bsonType: "int",
minimum: 0,
maximum: 150,
description: "必须是0-150之间的整数"
}
}
}
}
})

复制集(Replica Set)

配置复制集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 启动三个mongod实例
mongod --replSet rs0 --port 27017 --dbpath /data/db1
mongod --replSet rs0 --port 27018 --dbpath /data/db2
mongod --replSet rs0 --port 27019 --dbpath /data/db3

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

分片(Sharding)

分片集群架构

  • mongos:查询路由器
  • config servers:配置服务器
  • shards:分片服务器

启用分片

1
2
3
4
5
6
7
8
9
10
11
12
// 连接到mongos
mongos --configdb configReplSet/cfg1.example.net:27019,cfg2.example.net:27019,cfg3.example.net:27019

// 添加分片
sh.addShard("shard1.example.net:27018")
sh.addShard("shard2.example.net:27018")

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

// 对集合分片
sh.shardCollection("mydb.users", { username: "hashed" })

性能优化

1. 索引优化

  • 为查询频繁的字段创建索引
  • 使用复合索引优化多字段查询
  • 避免索引选择性低的字段

2. 查询优化

  • 使用投影减少返回字段
  • 使用limit限制结果集
  • 避免全表扫描

3. 连接优化

  • 使用连接池
  • 合理设置连接超时时间
  • 监控连接数

常用工具

1. MongoDB Compass

  • 官方GUI管理工具
  • 可视化查询和索引管理

2. Robo 3T

  • 轻量级MongoDB管理工具
  • 支持Shell命令

3. 命令行工具

  • mongo:交互式Shell
  • mongodump:备份工具
  • mongorestore:恢复工具

与Node.js集成

使用Mongoose

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const mongoose = require('mongoose');

// 连接数据库
mongoose.connect('mongodb://localhost:27017/mydb');

// 定义模式
const userSchema = new mongoose.Schema({
username: { type: String, required: true, unique: true },
email: { type: String, required: true, unique: true },
age: { type: Number, min: 0, max: 150 },
createdAt: { type: Date, default: Date.now }
});

// 创建模型
const User = mongoose.model('User', userSchema);

// 使用模型
const newUser = new User({
username: 'testuser',
email: 'test@example.com',
age: 25
});

newUser.save()
.then(user => console.log('User saved:', user))
.catch(err => console.error(err));

常见应用场景

  1. 内容管理系统:文章、评论、用户管理
  2. 实时分析:日志收集、用户行为分析
  3. 物联网:设备数据存储、传感器数据
  4. 移动应用:用户数据、消息推送
  5. 电商平台:商品目录、订单管理

优缺点分析

优点

  • 灵活的文档模型
  • 高性能和可扩展性
  • 丰富的查询语言
  • 自动分片和复制
  • 活跃的开源社区

缺点

  • 不支持复杂事务
  • 内存占用较高
  • 缺乏成熟的DBA工具
  • 数据一致性较弱

学习资源推荐

  • 官方文档https://docs.mongodb.com/
  • 在线课程:MongoDB University
  • 书籍:《MongoDB权威指南》、《MongoDB实战》
  • 实践项目:构建博客系统、实时聊天应用

总结

MongoDB作为NoSQL数据库的领导者,凭借其灵活的文档模型、高性能和易扩展性,在现代Web开发中占据重要地位。特别适合处理非结构化数据和需要快速迭代的应用场景。对于需要处理大量数据和高并发访问的现代应用,MongoDB是一个值得考虑的选择。