最流行的NoSQL文档数据库
MongoDB是一个面向文档的NoSQL数据库管理系统,使用BSON格式存储数据,非常适合存储非结构化或半结构化数据。
| 特性 | MongoDB | 关系数据库 |
|---|---|---|
| 数据模型 | 文档(BSON) | 表(行/列) |
| Schema | 灵活,动态 | 固定,需预定义 |
| 查询语言 | JavaScript类似 | SQL |
| 关系处理 | 嵌入或引用 | Join操作 |
| 扩展性 | 水平扩展(分片) | 垂直扩展 |
# 使用 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
# 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
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
// 显示所有数据库
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")
// 基础聚合
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" } } }
]
}
}
])
💡 常用聚合操作符:
// 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();
}
}
// 监听集合变化
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()
✨ 复制集优势:
// 启动配置服务器(配置服务器副本集)
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"]
}
}
}
])