MongoDB是一个开源的、面向文档的NoSQL数据库,由MongoDB Inc.开发,使用C++语言编写。它采用BSON(Binary JSON)格式存储数据,是现代Web应用开发中最流行的数据库之一。
MongoDB的设计目标是解决传统关系型数据库在Web 2.0时代面临的挑战:高并发读写、海量数据存储、高可扩展性需求。
以下是MongoDB在不同领域的具体应用案例和最佳实践:
场景描述:构建一个支持多种内容类型(文章、页面、媒体)的现代化内容管理系统。
// 内容文档模型
{
"_id": ObjectId(),
"title": "MongoDB入门指南",
"slug": "mongodb-introduction",
"content": "...",
"type": "article", // article, page, media
"status": "published", // draft, published, archived
"author": {
"_id": ObjectId(),
"name": "张三",
"email": "zhangsan@example.com"
},
"categories": ["数据库", "NoSQL"],
"tags": ["MongoDB", "数据库", "入门"],
"metadata": {
"views": 1000,
"comments": 50,
"likes": 200
},
"created_at": ISODate(),
"updated_at": ISODate()
}
// 媒体文档模型
{
"_id": ObjectId(),
"filename": "mongodb-logo.png",
"path": "/uploads/mongodb-logo.png",
"size": 102400,
"mime_type": "image/png",
"metadata": {
"width": 800,
"height": 600,
"alt_text": "MongoDB Logo"
},
"uploaded_by": ObjectId(),
"uploaded_at": ISODate()
}
// 查询已发布的文章,按创建时间倒序
db.content.find({
"type": "article",
"status": "published"
}).sort({ "created_at": -1 }).limit(10)
// 按分类查询内容
db.content.find({
"categories": "数据库"
})
// 增量更新浏览量
db.content.updateOne(
{ "_id": ObjectId("...") },
{ "$inc": { "metadata.views": 1 } }
)
场景描述:构建一个支持多角色、权限控制的用户认证系统。
// 用户文档模型
{
"_id": ObjectId(),
"username": "admin",
"email": "admin@example.com",
"password_hash": "$2a$10$...", // 加密后的密码
"roles": ["admin", "user"],
"permissions": ["read", "write", "delete"],
"profile": {
"first_name": "张",
"last_name": "三",
"avatar": "avatar.jpg",
"bio": "系统管理员"
},
"last_login": ISODate(),
"login_attempts": 0,
"lock_until": null,
"created_at": ISODate(),
"updated_at": ISODate()
}
// 会话文档模型
{
"_id": ObjectId(),
"user_id": ObjectId(),
"token": "jwt-token-here",
"expires_at": ISODate(),
"created_at": ISODate()
}
// 用户登录验证
db.users.findOne({
"$or": [
{ "username": "admin" },
{ "email": "admin@example.com" }
],
"lock_until": { "$lt": new Date() } // 确保账户未锁定
})
// 更新登录信息
db.users.updateOne(
{ "_id": ObjectId("...") },
{
"$set": {
"last_login": new Date(),
"login_attempts": 0
}
}
)
// 记录登录失败
db.users.updateOne(
{ "_id": ObjectId("...") },
{
"$inc": { "login_attempts": 1 },
"$set": { "lock_until": new Date(Date.now() + 3600000) } // 锁定1小时
}
)
场景描述:构建一个支持复杂产品属性、分类和搜索的电商产品目录系统。
// 产品文档模型
{
"_id": ObjectId(),
"name": "MongoDB Atlas云服务",
"sku": "MONGO-ATLAS-001",
"price": 99.99,
"currency": "USD",
"category": "数据库服务",
"subcategories": ["NoSQL", "云服务"],
"description": "...",
"features": [
"高可用性",
"自动扩展",
"全球分布"
],
"specs": {
"storage": "10GB",
"memory": "2GB",
"cpus": 2
},
"images": [
{
"url": "product1-main.jpg",
"alt": "Main Image",
"is_primary": true
},
{
"url": "product1-side.jpg",
"alt": "Side View",
"is_primary": false
}
],
"inventory": {
"quantity": 100,
"in_stock": true
},
"reviews": [
{
"user_id": ObjectId(),
"rating": 5,
"comment": "Excellent service!",
"created_at": ISODate()
}
],
"created_at": ISODate(),
"updated_at": ISODate()
}
// 按分类和价格范围查询产品
db.products.find({
"category": "数据库服务",
"price": { "$gte": 50, "$lte": 200 }
}).sort({ "price": 1 })
// 搜索产品(使用文本索引)
db.products.find({
"$text": { "$search": "MongoDB cloud" }
})
// 更新库存
db.products.updateOne(
{ "_id": ObjectId("...") },
{ "$set": { "inventory.quantity": 99 } }
)
// 添加评论
db.products.updateOne(
{ "_id": ObjectId("...") },
{
"$push": {
"reviews": {
"user_id": ObjectId("..."),
"rating": 4,
"comment": "Good product",
"created_at": new Date()
}
}
}
)
场景描述:存储和分析来自大量物联网设备的传感器数据。
// 设备文档模型
{
"_id": ObjectId(),
"device_id": "DEV-123456",
"name": "温度传感器",
"type": "temperature",
"location": {
"name": "服务器机房A",
"coordinates": [116.4074, 39.9042]
},
"metadata": {
"manufacturer": "SensorTech",
"model": "TS-1000",
"firmware_version": "1.0.0"
},
"status": "active",
"last_connected": ISODate(),
"created_at": ISODate()
}
// 传感器数据文档模型
{
"_id": ObjectId(),
"device_id": "DEV-123456",
"timestamp": ISODate(),
"readings": {
"temperature": 25.5,
"humidity": 45.2,
"pressure": 1013.25
},
"battery_level": 85,
"signal_strength": -65,
"location": {
"type": "Point",
"coordinates": [116.4074, 39.9042]
}
}
// 查询特定设备的最新数据
db.sensor_data.find({
"device_id": "DEV-123456"
}).sort({ "timestamp": -1 }).limit(1)
// 查询温度异常的设备数据
db.sensor_data.find({
"readings.temperature": { "$gt": 30 }
})
// 按时间范围聚合数据
db.sensor_data.aggregate([
{
"$match": {
"device_id": "DEV-123456",
"timestamp": {
"$gte": new Date(Date.now() - 86400000), // 过去24小时
"$lte": new Date()
}
}
},
{
"$group": {
"_id": {
"$dateToString": {
"format": "%Y-%m-%d %H:00:00",
"date": "$timestamp"
}
},
"avg_temperature": { "$avg": "$readings.temperature" },
"max_temperature": { "$max": "$readings.temperature" },
"min_temperature": { "$min": "$readings.temperature" }
}
},
{
"$sort": { "_id": 1 }
}
])
场景描述:收集、存储和分析应用程序日志数据。
// 日志文档模型
{
"_id": ObjectId(),
"timestamp": ISODate(),
"level": "info", // debug, info, warn, error, fatal
"service": "api-gateway",
"environment": "production",
"message": "User login successful",
"metadata": {
"user_id": "user123",
"ip_address": "192.168.1.1",
"user_agent": "Mozilla/5.0...",
"request_id": "req-7890",
"response_time": 150, // ms
"status_code": 200
},
"error": {
"code": "AUTH_ERROR",
"message": "Invalid token",
"stack": "Error: Invalid token\n at ..."
},
"tags": ["auth", "login"]
}
// 查询错误日志
db.logs.find({
"level": "error",
"environment": "production"
}).sort({ "timestamp": -1 }).limit(20)
// 按服务统计错误率
db.logs.aggregate([
{
"$match": {
"timestamp": {
"$gte": new Date(Date.now() - 3600000), // 过去1小时
"$lte": new Date()
}
}
},
{
"$group": {
"_id": "$service",
"total_logs": { "$sum": 1 },
"error_logs": {
"$sum": {
"$cond": [{ "$eq": ["$level", "error"] }, 1, 0]
}
}
}
},
{
"$project": {
"service": "$_id",
"error_rate": {
"$multiply": [
{ "$divide": ["$error_logs", "$total_logs"] },
100
]
}
}
},
{
"$sort": { "error_rate": -1 }
}
])
要理解MongoDB的价值,首先需要了解NoSQL和SQL数据库的根本区别。这两种数据库范式代表了不同的数据管理哲学。
MongoDB作为文档型数据库的代表,既保留了NoSQL的灵活性,又从4.0版本开始支持多文档ACID事务,结合了两者的优势。它特别适合处理半结构化数据,如用户配置文件、产品目录、日志数据等。
MongoDB提供了多种安装方式,包括社区版和企业版。对于学习和开发,我们推荐使用社区版。
# 添加MongoDB的Homebrew仓库
tap mongodb/brew
# 安装MongoDB社区版
brew install mongodb-community
# 启动MongoDB服务
brew services start mongodb-community
# 导入MongoDB的GPG密钥
wget -qO - https://www.mongodb.org/static/pgp/server-7.0.asc | sudo apt-key add -
# 添加MongoDB软件源
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
# 启动MongoDB服务
sudo systemctl start mongod
# 设置开机自启
sudo systemctl enable mongod
1. 访问官网下载:https://www.mongodb.com/try/download/community
2. 运行安装程序,选择"Complete"完整安装
3. 安装完成后,MongoDB会作为Windows服务自动启动
# 拉取MongoDB官方镜像
docker pull mongo:latest
# 运行MongoDB容器
docker run -d --name mongodb -p 27017:27017 -v mongodb_data:/data/db mongo
# 连接到MongoDB容器
docker exec -it mongodb mongosh
MongoDB安装包包含以下核心组件:
安装完成后,需要验证MongoDB是否正确安装并能够正常启动。
# 检查MongoDB服务器版本
mongod --version
# 检查MongoDB Shell版本
mongosh --version
MongoDB Compass是官方提供的图形化管理工具,提供了直观的界面来管理MongoDB数据库。
从MongoDB官网下载并安装对应系统的Compass版本:
mongodb://localhost:27017mongodb://username:password@hostname:27017Compass提供了可视化的查询构建器:
{ "age": { "$gt": 18 } }可视化构建聚合管道:
支持查看和分析地理空间数据:
优化的时间序列数据查看器:
不同系统的启动方式:
# 使用Homebrew服务管理
brew services start mongodb-community
# 或者手动启动
mongod --config /usr/local/etc/mongod.conf
# 使用systemctl启动服务
sudo systemctl start mongod
# 检查服务状态
sudo systemctl status mongod
# 设置开机自启
sudo systemctl enable mongod
# 通过服务管理器启动
net start MongoDB
# 或者通过命令行启动
"C:\Program Files\MongoDB\Server\7.0\bin\mongod.exe" --dbpath="C:\data\db"
# 启动MongoDB Shell
mongosh
# 或者指定连接参数
mongosh "mongodb://localhost:27017"
# 在Shell中测试基本命令
> db.version() # 查看数据库版本
> show dbs # 显示所有数据库
> exit # 退出Shell
MongoDB默认使用27017端口,数据存储在/data/db目录下。如果启动失败,请检查:
MongoDB Shell(mongosh)是MongoDB的交互式JavaScript接口,用于管理数据库和执行操作。
# 连接到本地MongoDB实例
mongosh
# 连接到远程服务器
mongosh "mongodb://username:password@hostname:27017/database"
# 带认证的连接
mongosh --authenticationDatabase admin --username admin --password password
// 显示所有数据库(空数据库不会显示)
show dbs
// 显示当前使用的数据库
db
// 切换或创建数据库(数据库不存在时会自动创建)
use mydatabase
// 显示当前数据库的状态
db.stats()
// 显示数据库版本
db.version()
// 显示当前数据库的所有集合
show collections
// 创建集合(可选)
db.createCollection("users")
// 显示集合信息
db.users.stats()
// 重命名集合
db.users.renameCollection("members")
MongoDB提供了丰富的查询功能,从基本的等值查询到复杂的聚合操作,满足各种数据检索需求。
// 查询所有文档
db.users.find()
// 格式化输出
db.users.find().pretty()
// 等值查询
db.users.find({ "age": 25 })
// 多条件查询
db.users.find({ "age": 25, "name": "张三" })
// 范围查询
db.users.find({ "age": { "$gt": 18, "$lt": 30 } })
// 逻辑或查询
db.users.find({ "$or": [{ "age": 25 }, { "name": "张三" }] })
// 逻辑非查询
db.users.find({ "age": { "$not": { "$eq": 25 } } })
// 只返回指定字段(1表示包含,0表示排除)
db.users.find({ "age": { "$gt": 18 } }, { "name": 1, "age": 1, "_id": 0 })
// 排除指定字段
db.users.find({}, { "password": 0 })
// 升序排序(1表示升序)
db.users.find().sort({ "age": 1 })
// 降序排序(-1表示降序)
db.users.find().sort({ "age": -1 })
// 多字段排序
db.users.find().sort({ "age": -1, "name": 1 })
// 限制返回文档数量
db.users.find().limit(10)
// 跳过指定数量的文档
db.users.find().skip(10)
// 分页查询(第2页,每页10条)
db.users.find().skip(10).limit(10)
// 数组包含查询
db.users.find({ "hobbies": "篮球" })
// 数组包含多个元素
db.users.find({ "hobbies": { "$all": ["篮球", "阅读"] } })
// 数组长度查询
db.users.find({ "hobbies": { "$size": 3 } })
// 数组元素范围查询
db.users.find({ "hobbies.0": "篮球" })
// 数组元素条件查询
db.users.find({ "scores": { "$elemMatch": { "$gt": 80, "$lt": 90 } } })
// 嵌套文档等值查询
db.users.find({ "address.city": "北京" })
// 嵌套文档范围查询
db.users.find({ "address.zipcode": { "$gt": 100000 } })
// 完整嵌套文档匹配
db.users.find({ "address": { "city": "北京", "district": "朝阳区" } })
// 正则表达式查询(用户名以"张"开头)
db.users.find({ "name": { "$regex": "^张", "$options": "i" } })
// 包含指定字符
db.users.find({ "email": { "$regex": "@example\.com" } })
// 不区分大小写
db.users.find({ "name": { "$regex": "zhang", "$options": "i" } })
// 按数据类型查询
db.users.find({ "age": { "$type": "number" } })
db.users.find({ "name": { "$type": "string" } })
db.users.find({ "created_at": { "$type": "date" } })
// 存在性查询
db.users.find({ "email": { "$exists": true } })
db.users.find({ "phone": { "$exists": false } })
// 查找指定范围内的位置
db.places.find({
"location": {
"$near": {
"$geometry": {
"type": "Point",
"coordinates": [116.4074, 39.9042]
},
"$maxDistance": 1000 // 1000米
}
}
})
// 查找指定多边形内的位置
db.places.find({
"location": {
"$geoWithin": {
"$geometry": {
"type": "Polygon",
"coordinates": [[
[116.4, 39.9],
[116.5, 39.9],
[116.5, 40.0],
[116.4, 40.0],
[116.4, 39.9]
]]
}
}
}
})
索引是提高MongoDB查询性能的关键,合理的索引设计可以显著提升查询速度。
// 创建单字段索引
db.users.createIndex({ "name": 1 }) // 1表示升序,-1表示降序
// 创建复合索引
db.users.createIndex({ "age": 1, "name": 1 })
// 创建唯一索引
db.users.createIndex({ "email": 1 }, { "unique": true })
// 创建多键索引(自动为数组字段创建)
db.users.createIndex({ "hobbies": 1 })
// 创建文本索引
db.users.createIndex({ "content": "text" })
// 创建TTL索引(24小时后过期)
db.sessions.createIndex({ "created_at": 1 }, { "expireAfterSeconds": 86400 })
// 创建地理空间索引
db.places.createIndex({ "location": "2dsphere" })
// 查看集合的所有索引
db.users.getIndexes()
// 查看索引大小
db.users.totalIndexSize()
// 删除索引
db.users.dropIndex({ "name": 1 })
// 删除所有索引(保留_id索引)
db.users.dropIndexes()
// 分析查询执行计划
db.users.find({ "age": { "$gt": 20 } }).explain()
// 详细分析
db.users.find({ "age": { "$gt": 20 } }).explain("executionStats")
// 分析查询阶段
db.users.find({ "age": { "$gt": 20 } }).explain("allPlansExecution")
// 显示帮助信息
help
// 显示数据库命令帮助
db.help()
// 显示集合命令帮助
db.users.help()
// 退出Shell
exit
// 或者使用快捷键 Ctrl+D
MongoDB Shell基于JavaScript引擎,支持:
聚合框架是MongoDB中强大的数据处理工具,用于执行数据转换、分组、统计和分析操作。
聚合操作通过管道(pipeline)方式处理数据,每个管道阶段对数据进行特定的转换:
// 聚合管道语法
db.collection.aggregate([
{ "$stage1": { /* 阶段1操作 */ } },
{ "$stage2": { /* 阶段2操作 */ } },
// 更多阶段...
])
// $match - 过滤文档,类似于find()
{ "$match": { "age": { "$gt": 18 } } }
// $project - 投影字段,类似于find()的第二个参数
{ "$project": { "name": 1, "age": 1, "_id": 0 } }
// $redact - 基于文档内容过滤文档
{ "$redact": { "$cond": [{ "$gt": ["$age", 18] }, "$$DESCEND", "$$PRUNE"] } }
// $group - 分组文档并计算聚合值
{ "$group": {
"_id": "$category", // 分组字段
"total": { "$sum": 1 }, // 计数
"avgPrice": { "$avg": "$price" }, // 平均值
"maxPrice": { "$max": "$price" }, // 最大值
"minPrice": { "$min": "$price" }, // 最小值
"sumPrice": { "$sum": "$price" }, // 求和
"firstItem": { "$first": "$name" }, // 第一个元素
"lastItem": { "$last": "$name" } // 最后一个元素
} }
// $sortByCount - 分组并按计数排序
{ "$sortByCount": "$category" }
// $sort - 排序文档
{ "$sort": { "age": -1, "name": 1 } }
// $limit - 限制返回文档数量
{ "$limit": 10 }
// $skip - 跳过指定数量的文档
{ "$skip": 10 }
// $sample - 随机抽样文档
{ "$sample": { "size": 5 } }
// $unwind - 展开数组字段
{ "$unwind": "$hobbies" }
// 展开数组并处理空数组
{ "$unwind": { "path": "$hobbies", "preserveNullAndEmptyArrays": true } }
// $addToSet - 向数组添加唯一值
{ "$addToSet": "$tag" }
// $push - 向数组添加值
{ "$push": "$tag" }
// $arrayElemAt - 获取数组指定位置的元素
{ "$arrayElemAt": ["$hobbies", 0] }
// $filter - 过滤数组元素
{ "$filter": {
"input": "$hobbies",
"as": "hobby",
"cond": { "$eq": ["$$hobby", "篮球"] }
} }
// $mergeObjects - 合并文档
{ "$mergeObjects": ["$address", "$contact"] }
// $replaceRoot - 将指定字段作为根文档
{ "$replaceRoot": { "newRoot": "$user" } }
// $addFields - 添加新字段
{ "$addFields": { "fullName": { "$concat": ["$firstName", " ", "$lastName"] } } }
// $set - 同$addFields,添加或修改字段
{ "$set": { "status": "active" } }
// $unset - 删除字段
{ "$unset": ["password", "token"] }
// 数学操作符
{ "$add": ["$price", 10] } // 加法
{ "$subtract": ["$price", 5] } // 减法
{ "$multiply": ["$price", 2] } // 乘法
{ "$divide": ["$price", 2] } // 除法
{ "$mod": ["$price", 10] } // 取模
// 日期操作符
{ "$year": "$createdAt" } // 提取年份
{ "$month": "$createdAt" } // 提取月份
{ "$dayOfMonth": "$createdAt" } // 提取日期
{ "$hour": "$createdAt" } // 提取小时
{ "$minute": "$createdAt" } // 提取分钟
{ "$second": "$createdAt" } // 提取秒
// 日期差值
{ "$subtract": [new Date(), "$createdAt"] } // 计算时间差(毫秒)
// $concat - 连接字符串
{ "$concat": ["$firstName", " ", "$lastName"] }
// $toUpper - 转换为大写
{ "$toUpper": "$name" }
// $toLower - 转换为小写
{ "$toLower": "$name" }
// $trim - 去除首尾空格
{ "$trim": { "input": "$name" } }
// $split - 分割字符串
{ "$split": ["$email", "@"] }
// $substrCP - 截取字符串
{ "$substrCP": ["$name", 0, 3] } // 从索引0开始,截取3个字符
// 按年龄段统计用户数量
db.users.aggregate([
{ "$match": { "status": "active" } },
{ "$project": {
"ageGroup": {
"$switch": {
"branches": [
{ "case": { "$lt": ["$age", 18] }, "then": "未成年人" },
{ "case": { "$and": [{ "$gte": ["$age", 18] }, { "$lt": ["$age", 30] }] }, "then": "青年" },
{ "case": { "$and": [{ "$gte": ["$age", 30] }, { "$lt": ["$age", 50] }] }, "then": "中年" },
{ "case": { "$gte": ["$age", 50] }, "then": "老年" }
],
"default": "未知"
}
}
} },
{ "$group": {
"_id": "$ageGroup",
"count": { "$sum": 1 }
} },
{ "$sort": { "count": -1 } }
])
// 按月份统计订单金额和数量
db.orders.aggregate([
{ "$match": {
"created_at": {
"$gte": new Date("2024-01-01"),
"$lte": new Date("2024-12-31")
}
} },
{ "$project": {
"month": { "$month": "$created_at" },
"year": { "$year": "$created_at" },
"amount": "$total_amount"
} },
{ "$group": {
"_id": { "year": "$year", "month": "$month" },
"totalAmount": { "$sum": "$amount" },
"orderCount": { "$sum": 1 },
"avgAmount": { "$avg": "$amount" }
} },
{ "$sort": { "_id.year": 1, "_id.month": 1 } },
{ "$project": {
"year": "$_id.year",
"month": "$_id.month",
"totalAmount": 1,
"orderCount": 1,
"avgAmount": { "$round": ["$avgAmount", 2] },
"_id": 0
} }
])
// 分析库存状态,按分类统计
db.products.aggregate([
{ "$addFields": {
"stockStatus": {
"$cond": [
{ "$lte": ["$inventory.quantity", 0] },
"缺货",
{
"$cond": [
{ "$lte": ["$inventory.quantity", 10] },
"库存不足",
"库存充足"
]
}
]
}
} },
{ "$group": {
"_id": { "category": "$category", "status": "$stockStatus" },
"productCount": { "$sum": 1 },
"totalValue": {
"$sum": { "$multiply": ["$price", "$inventory.quantity"] }
}
} },
{ "$sort": { "_id.category": 1, "productCount": -1 } }
])
// 分析用户活跃度,计算最近30天的行为统计
db.user_actions.aggregate([
{ "$match": {
"action_time": {
"$gte": new Date(Date.now() - 30 * 24 * 60 * 60 * 1000)
}
} },
{ "$group": {
"_id": "$user_id",
"actionCount": { "$sum": 1 },
"lastAction": { "$max": "$action_time" },
"actionTypes": { "$addToSet": "$action_type" }
} },
{ "$addFields": {
"daysSinceLastAction": {
"$floor": {
"$divide": [
{ "$subtract": [new Date(), "$lastAction"] },
24 * 60 * 60 * 1000
]
}
},
"activeDays": {
"$size": "$actionTypes"
}
} },
{ "$project": {
"userId": "$_id",
"actionCount": 1,
"lastAction": 1,
"daysSinceLastAction": 1,
"activeDays": 1,
"_id": 0
} },
{ "$sort": { "actionCount": -1 } },
{ "$limit": 10 }
])
// 关联查询用户和订单信息
db.users.aggregate([
{ "$match": { "status": "active" } },
{ "$lookup": {
"from": "orders",
"localField": "_id",
"foreignField": "user_id",
"as": "user_orders"
} },
{ "$addFields": {
"orderCount": { "$size": "$user_orders" },
"totalSpent": {
"$sum": "$user_orders.total_amount"
}
} },
{ "$project": {
"name": 1,
"email": 1,
"orderCount": 1,
"totalSpent": 1,
"_id": 0
} }
])
// 多维度分析商品数据
db.products.aggregate([
{ "$facet": {
"byCategory": [
{ "$group": {
"_id": "$category",
"count": { "$sum": 1 },
"avgPrice": { "$avg": "$price" }
} },
{ "$sort": { "count": -1 } }
],
"byStockStatus": [
{ "$addFields": {
"stockStatus": {
"$cond": [
{ "$lte": ["$inventory.quantity", 0] },
"缺货",
"有货"
]
}
} },
{ "$group": {
"_id": "$stockStatus",
"count": { "$sum": 1 }
} }
],
"priceStats": [
{ "$group": {
"_id": null,
"minPrice": { "$min": "$price" },
"maxPrice": { "$max": "$price" },
"avgPrice": { "$avg": "$price" },
"totalProducts": { "$sum": 1 }
} }
]
} }
])
// 查找用户的间接关注关系
db.users.aggregate([
{ "$match": { "username": "user1" } },
{ "$graphLookup": {
"from": "follows",
"startWith": "$ _id",
"connectFromField": "follower_id",
"connectToField": "following_id",
"as": "followingChain",
"maxDepth": 3
} }
])
db.collection.aggregate([...], { "allowDiskUse": true })
理解MongoDB的核心概念是掌握其使用的关键。这些概念与传统关系型数据库有所不同,体现了文档数据库的独特设计哲学。
数据库是MongoDB中的顶级数据容器,类似于关系型数据库中的database概念。
admin - 系统管理数据库,存储用户权限信息local - 存储本地服务器的特定数据,不会被复制config - 在分片集群中存储分片配置信息集合是文档的容器,类似于关系型数据库中的表,但有重要区别:
文档是MongoDB中的基本数据单元,使用BSON格式存储:
字段是文档中的键值对,支持丰富的数据类型:
BSON(Binary JSON)是MongoDB的核心数据格式,相比JSON有重要优势:
BSON支持的数据类型:Double、String、Object、Array、Binary Data、ObjectId、Boolean、Date、Null、Regular Expression、JavaScript、Symbol、JavaScript (with scope)、32-bit integer、Timestamp、64-bit integer、Decimal128、Min key、Max key
ObjectId是MongoDB文档的默认主键类型,具有分布式友好的设计:
// ObjectId的结构:12字节的十六进制字符串
// 格式:时间戳(4) + 机器标识(3) + 进程ID(2) + 计数器(3)
{
"_id": ObjectId("507f1f77bcf86cd799439011")
}
MongoDB的存储系统是其高性能的关键,理解其底层存储原理有助于优化应用设计。
MongoDB支持多种存储引擎,默认使用WiredTiger(从3.2版本开始):
MongoDB在文件系统中的存储结构:
// 数据文件结构
/data/db/
├── WiredTiger // WiredTiger元数据
├── WiredTiger.lock // 锁文件
├── collection-.wt // 集合数据文件
├── index-.wt // 索引数据文件
├── _mdb_catalog.wt // 系统目录
└── mongod.lock // MongoDB锁文件
良好的数据模型设计是MongoDB性能的基础,以下是一些关键原则:
// 用户文档(嵌入地址信息)
{
"_id": ObjectId("507f1f77bcf86cd799439011"),
"name": "张三",
"email": "zhangsan@example.com",
"address": {
"city": "北京",
"district": "朝阳区",
"street": "建国门外大街"
}
}
// 用户文档
{
"_id": ObjectId("507f1f77bcf86cd799439011"),
"name": "张三",
"email": "zhangsan@example.com",
"address_id": ObjectId("507f1f77bcf86cd799439012")
}
// 地址文档
{
"_id": ObjectId("507f1f77bcf86cd799439012"),
"city": "北京",
"district": "朝阳区",
"street": "建国门外大街"
}
MongoDB提供了多种编程语言的驱动程序,方便在不同技术栈中集成使用。以下是常见语言的集成示例:
方案1:使用官方MongoDB Node.js驱动
// 使用npm安装
npm install mongodb
// 或使用yarn
yarn add mongodb
const { MongoClient } = require('mongodb');
// MongoDB连接字符串
const uri = 'mongodb://localhost:27017';
const client = new MongoClient(uri);
async function main() {
try {
// 连接到MongoDB
await client.connect();
console.log('Connected to MongoDB');
// 获取数据库
const db = client.db('mydb');
// 获取集合
const usersCollection = db.collection('users');
// 插入文档
const insertResult = await usersCollection.insertOne({
name: '张三',
age: 25,
email: 'zhangsan@example.com',
hobbies: ['篮球', '阅读', '编程'],
created_at: new Date()
});
console.log('Inserted document:', insertResult.insertedId);
// 查询文档
const findResult = await usersCollection.find({ age: { $gt: 18 } }).toArray();
console.log('Found documents:', findResult);
// 更新文档
const updateResult = await usersCollection.updateOne(
{ _id: insertResult.insertedId },
{ $set: { age: 26 } }
);
console.log('Updated document:', updateResult.modifiedCount);
// 删除文档
const deleteResult = await usersCollection.deleteOne(
{ _id: insertResult.insertedId }
);
console.log('Deleted document:', deleteResult.deletedCount);
} catch (error) {
console.error('Error:', error);
} finally {
// 关闭连接
await client.close();
console.log('Connection closed');
}
}
// 执行主函数
main().catch(console.error);
方案2:使用Mongoose ORM
// 安装Mongoose
npm install mongoose
// 或使用yarn
yarn add mongoose
const mongoose = require('mongoose');
// 连接到MongoDB
mongoose.connect('mongodb://localhost:27017/mydb', {
useNewUrlParser: true,
useUnifiedTopology: true
});
// 定义模式
const userSchema = new mongoose.Schema({
name: String,
age: Number,
email: {
type: String,
unique: true,
required: true
},
hobbies: [String],
created_at: {
type: Date,
default: Date.now
}
});
// 创建模型
const User = mongoose.model('User', userSchema);
// 异步函数处理
async function mongooseExample() {
try {
// 创建用户
const user = new User({
name: '李四',
age: 30,
email: 'lisi@example.com',
hobbies: ['游泳', '摄影']
});
// 保存用户
const savedUser = await user.save();
console.log('Saved user:', savedUser);
// 查询用户
const foundUser = await User.findOne({ email: 'lisi@example.com' });
console.log('Found user:', foundUser);
// 更新用户
foundUser.age = 31;
const updatedUser = await foundUser.save();
console.log('Updated user:', updatedUser);
// 删除用户
await User.deleteOne({ _id: savedUser._id });
console.log('User deleted');
} catch (error) {
console.error('Error:', error);
} finally {
// 关闭连接
mongoose.connection.close();
console.log('Connection closed');
}
}
// 执行示例
mongooseExample();
使用PyMongo驱动
# 使用pip安装
pip install pymongo
# 或使用conda
conda install -c anaconda pymongo
from pymongo import MongoClient
from datetime import datetime
# 连接到MongoDB
client = MongoClient('mongodb://localhost:27017/')
# 获取数据库
db = client['mydb']
# 获取集合
users_collection = db['users']
# 插入文档
user_data = {
'name': '王五',
'age': 28,
'email': 'wangwu@example.com',
'hobbies': ['音乐', '旅行'],
'created_at': datetime.now()
}
insert_result = users_collection.insert_one(user_data)
print(f'Inserted document with ID: {insert_result.inserted_id}')
# 查询文档
print('\nAll users:')
for user in users_collection.find():
print(user)
# 条件查询
print('\nUsers older than 25:')
for user in users_collection.find({'age': {'$gt': 25}}):
print(user)
# 更新文档
update_result = users_collection.update_one(
{'_id': insert_result.inserted_id},
{'$set': {'age': 29}}
)
print(f'\nUpdated {update_result.modified_count} document(s)')
# 删除文档
delete_result = users_collection.delete_one(
{'_id': insert_result.inserted_id}
)
print(f'Deleted {delete_result.deleted_count} document(s)')
# 关闭连接
client.close()
print('Connection closed')
使用MongoDB Java驱动
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>4.10.0</version>
</dependency>
import com.mongodb.client.*;
import org.bson.Document;
import java.util.Arrays;
import java.util.Date;
public class MongoDBJavaExample {
public static void main(String[] args) {
// 连接到MongoDB
MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017");
// 获取数据库
MongoDatabase database = mongoClient.getDatabase("mydb");
// 获取集合
MongoCollection<Document> collection = database.getCollection("users");
// 插入文档
Document user = new Document("name", "赵六")
.append("age", 35)
.append("email", "zhaoliu@example.com")
.append("hobbies", Arrays.asList("烹饪", "钓鱼"))
.append("created_at", new Date());
collection.insertOne(user);
System.out.println("Inserted document: " + user.getObjectId("_id"));
// 查询文档
System.out.println("\nAll users:");
FindIterable<Document> documents = collection.find();
for (Document doc : documents) {
System.out.println(doc.toJson());
}
// 条件查询
System.out.println("\nUsers with age > 30:");
Document filter = new Document("age", new Document("$gt", 30));
FindIterable<Document> filteredDocs = collection.find(filter);
for (Document doc : filteredDocs) {
System.out.println(doc.toJson());
}
// 更新文档
collection.updateOne(
new Document("_id", user.getObjectId("_id")),
new Document("$set", new Document("age", 36))
);
System.out.println("Document updated");
// 删除文档
collection.deleteOne(new Document("_id", user.getObjectId("_id")));
System.out.println("Document deleted");
// 关闭连接
mongoClient.close();
System.out.println("Connection closed");
}
}
使用MongoDB PHP扩展
// 使用Composer安装
composer require mongodb/mongodb
<?php
require 'vendor/autoload.php';
use MongoDB\Client;
// 连接到MongoDB
$client = new Client('mongodb://localhost:27017');
// 获取数据库
$db = $client->mydb;
// 获取集合
$collection = $db->users;
// 插入文档
$user = [
'name' => '孙七',
'age' => 32,
'email' => 'sunqi@example.com',
'hobbies' => ['爬山', '露营'],
'created_at' => new MongoDB\BSON\UTCDateTime()
];
$insertResult = $collection->insertOne($user);
echo "Inserted document with ID: " . $insertResult->getInsertedId() . "\n";
// 查询文档
echo "\nAll users:\n";
$documents = $collection->find();
foreach ($documents as $document) {
var_dump($document);
}
// 条件查询
echo "\nUsers with age > 30:\n";
$filteredDocuments = $collection->find(['age' => ['$gt' => 30]]);
foreach ($filteredDocuments as $document) {
var_dump($document);
}
// 更新文档
$updateResult = $collection->updateOne(
['_id' => $insertResult->getInsertedId()],
['$set' => ['age' => 33]]
);
echo "Updated " . $updateResult->getModifiedCount() . " document(s)\n";
// 删除文档
$deleteResult = $collection->deleteOne(
['_id' => $insertResult->getInsertedId()]
);
echo "Deleted " . $deleteResult->getDeletedCount() . " document(s)\n";
// 关闭连接(PHP会自动关闭)
echo "Connection closed\n";
?>
除了本地部署,还可以使用MongoDB Atlas等云服务:
// Node.js连接Atlas
const uri = 'mongodb+srv://username:password@cluster0.mongodb.net/mydb?retryWrites=true&w=majority';
// Python连接Atlas
client = MongoClient('mongodb+srv://username:password@cluster0.mongodb.net/mydb?retryWrites=true&w=majority');
现在让我们通过一个完整的实战案例来体验MongoDB的基本操作流程。
// 切换到mydb数据库(如果不存在会自动创建)
use mydb
// 验证当前数据库
db
// 输出:mydb
原理说明:use命令用于切换数据库。如果数据库不存在,MongoDB会在第一次插入数据时自动创建它。
// 向users集合插入一条用户文档
db.users.insertOne({
name: "张三",
age: 25,
email: "zhangsan@example.com",
created_at: new Date(),
hobbies: ["篮球", "阅读", "编程"],
address: {
city: "北京",
district: "朝阳区",
street: "建国门外大街"
}
})
执行结果:
{
acknowledged: true,
insertedId: ObjectId("507f1f77bcf86cd799439011")
}
原理说明:
insertOne()方法插入单个文档_id字段// 查询users集合中的所有文档
db.users.find()
// 格式化输出,便于阅读
db.users.find().pretty()
执行结果:
{
"_id": ObjectId("507f1f77bcf86cd799439011"),
"name": "张三",
"age": 25,
"email": "zhangsan@example.com",
"created_at": ISODate("2024-01-01T10:30:00Z"),
"hobbies": ["篮球", "阅读", "编程"],
"address": {
"city": "北京",
"district": "朝阳区",
"street": "建国门外大街"
}
}
// 插入多条文档
db.users.insertMany([
{
name: "李四",
age: 30,
email: "lisi@example.com",
created_at: new Date(),
hobbies: ["游泳", "摄影"],
address: {
city: "上海",
district: "浦东新区"
}
},
{
name: "王五",
age: 28,
email: "wangwu@example.com",
created_at: new Date(),
hobbies: ["音乐", "旅行"],
profession: "软件工程师" // 注意:这个文档有额外的字段
}
])
原理说明:
insertMany()可以批量插入文档,提高效率_id和创建时间// 显示所有数据库(现在mydb会显示,因为有数据了)
show dbs
// 显示当前数据库的所有集合
show collections
// 查看users集合的统计信息
db.users.stats()
通过这个实战案例,我们体验了MongoDB的核心特性:
通过以下练习题来巩固本课学到的MongoDB基础知识和高级特性:
pretty()格式化输出show collections和show dbs验证数据库状态db.students.stats())db.help()和db.students.help()查看可用命令explain()分析查询性能$lookup连接多个集合的数据$facet同时执行多个聚合操作为了更好掌握MongoDB,建议:
性能优化是MongoDB生产环境中的关键考虑因素,以下是全面的性能优化策略和最佳实践:
// Linux系统建议设置
vm.swappiness = 10
// 关闭透明大页
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
// 在/etc/security/limits.conf中添加
* soft nofile 65536
* hard nofile 65536
* soft nproc 65536
* hard nproc 65536
// mongod.conf配置示例
systemLog:
destination: file
path: /var/log/mongodb/mongod.log
logAppend: true
storage:
dbPath: /var/lib/mongodb
journal:
enabled: true
wiredTiger:
engineConfig:
cacheSizeGB: 4 # 根据系统内存调整,通常为系统内存的50%
journalCompressor: snappy
collectionConfig:
blockCompressor: snappy
indexConfig:
prefixCompression: true
processManagement:
fork: true
pidFilePath: /var/run/mongodb/mongod.pid
net:
port: 27017
bindIp: 127.0.0.1 # 生产环境应设置为特定IP
security:
authorization: enabled # 启用认证
replication:
replSetName: rs0 # 副本集名称
sharding:
clusterRole: shardsvr # 分片服务器角色
// 查询:db.users.find({ age: { $gt: 18 } }, { name: 1, age: 1 })
// 优化:创建复合索引 db.users.createIndex({ age: 1, name: 1 })
// 创建索引:{ a: 1, b: 1, c: 1 }
// 自动支持:{ a: 1 }, { a: 1, b: 1 } 查询
// 好的索引字段:email, username(唯一性高)
// 差的索引字段:gender, status(唯一性低)
// 不好的查询
db.users.find({ age: { $gt: 18 } }) // 返回所有字段
// 好的查询
db.users.find({ age: { $gt: 18 } }, { name: 1, age: 1, _id: 0 }) // 只返回需要的字段
// 批量插入
db.users.insertMany([{...}, {...}, {...}])
// 批量更新
db.users.updateMany({ status: "inactive" }, { $set: { status: "deleted" } })
// 不好的查询(无索引)
db.users.find({ $where: "this.age > 18" }) // 性能差
// 好的查询(使用索引)
db.users.find({ age: { $gt: 18 } }) // 使用age字段索引
// 不好的分页(skip会扫描跳过的文档)
db.users.find().skip(10000).limit(10)
// 好的分页(使用游标)
db.users.find({ _id: { $gt: lastId } }).limit(10)
// 不好的命名
{ "firstName": "John", "lastName": "Doe" }
// 好的命名
{ "fn": "John", "ln": "Doe" }
// 使用db.serverStatus()查看
db.serverStatus().opcounters
// 监控慢查询
db.setProfilingLevel(1, { slowms: 100 }) // 记录超过100ms的查询
// 查看缓存使用
db.serverStatus().wiredTiger.cache
// 查看磁盘使用
db.serverStatus().diskSpace
// 查看当前连接
db.serverStatus().connections
// 重建集合的所有索引
db.collection.reIndex()
// 或重建特定索引
db.collection.reIndex({ field: 1 })
// 压缩集合
db.collection.compact()
// 在mongod.conf中配置
systemLog:
logRotate: reopen
destination: file
path: /var/log/mongodb/mongod.log
logAppend: true
// 备份数据库
mongodump --db mydb --out /backup/$(date +%Y%m%d)
// 恢复数据库
mongorestore --db mydb /backup/20240101/mydb
// 在副本集配置中设置
{ "_id": "rs0", "members": [...], "settings": { "electionTimeoutMillis": 10000 } }
// 查看副本集状态
rs.status()
// 查看复制延迟
rs.printSlaveReplicationInfo()
安全性是MongoDB生产环境中的关键考虑因素,同时可靠的备份策略确保数据不会丢失。以下是详细的安全配置和备份策略指南:
// 创建管理员用户
use admin
db.createUser({
user: "admin",
pwd: "SecureAdminPassword123",
roles: ["root"]
})
// 创建应用用户(最小权限)
use myapp
db.createUser({
user: "appuser",
pwd: "AppPassword123",
roles: [
{ role: "readWrite", db: "myapp" }
]
})
// 创建只读用户
use myapp
db.createUser({
user: "readonly",
pwd: "ReadPassword123",
roles: [
{ role: "read", db: "myapp" }
]
})
// mongod.conf
security:
authorization: enabled
// MongoDB Shell连接
mongo --host localhost --port 27017 -u admin -p SecureAdminPassword123 --authenticationDatabase admin
// 应用程序连接字符串
mongodb://admin:SecureAdminPassword123@localhost:27017/myapp?authSource=admin
// 启用密码强度检查
db.adminCommand({
setParameter: 1,
passwordPolicy: {
enabled: true,
minimumLength: 8,
requireUpperCase: true,
requireLowerCase: true,
requireDigits: true,
requireSpecialCharacters: true
}
})
// mongod.conf
net:
bindIp: 192.168.1.100,127.0.0.1 // 只监听指定IP
port: 27017
// 允许特定IP访问MongoDB端口
iptables -A INPUT -p tcp --dport 27017 -s 192.168.1.0/24 -j ACCEPT
// 拒绝其他所有访问
iptables -A INPUT -p tcp --dport 27017 -j DROP
// PowerShell命令
New-NetFirewallRule -DisplayName "MongoDB" -Direction Inbound -Protocol TCP -LocalPort 27017 -RemoteAddress 192.168.1.0/24 -Action Allow
// 生成SSL证书
openssl req -newkey rsa:2048 -new -x509 -days 365 -nodes -out mongodb-cert.crt -keyout mongodb-cert.key
cat mongodb-cert.key mongodb-cert.crt > mongodb.pem
// mongod.conf配置
net:
ssl:
mode: requireSSL
PEMKeyFile: /path/to/mongodb.pem
CAFile: /path/to/ca.pem
// MongoDB Shell连接
mongo --host localhost --port 27017 --ssl --sslCAFile /path/to/ca.pem -u admin -p
// 应用程序连接字符串
mongodb://admin:password@localhost:27017/myapp?authSource=admin&ssl=true&sslCAFile=/path/to/ca.pem
// mongod.conf配置
security:
enableEncryption: true
encryptionKeyFile: /path/to/keyfile
// 查询时脱敏处理
db.users.aggregate([
{ $project: {
_id: 1,
name: 1,
email: { $concat: [{ $substr: ["$email", 0, 3] }, "***", { $substr: ["$email", { $indexOfCP: ["$email", "@"] }, -1] }] }
}}
])
// 备份单个数据库
mongodump --db myapp --out /backup/$(date +%Y%m%d)
// 备份所有数据库
mongodump --out /backup/$(date +%Y%m%d)
// 压缩备份
mongodump --db myapp --gzip --out /backup/$(date +%Y%m%d)
// 远程备份
mongodump --host mongodb.example.com --port 27017 --db myapp --out /backup/$(date +%Y%m%d)
// 恢复单个数据库
mongorestore --db myapp /backup/20240101/myapp
// 恢复压缩备份
mongorestore --db myapp --gzip /backup/20240101/myapp
// 覆盖现有数据
mongorestore --db myapp --drop /backup/20240101/myapp
// 使用oplog进行时间点恢复
mongorestore --db myapp --oplogReplay /backup/20240101/myapp
// 恢复到特定时间
mongorestore --db myapp --oplogReplay --oplogLimit "2024-01-01T12:00:00Z" /backup/20240101/myapp
// 验证备份
mongorestore --db test_restore --drop /backup/20240101/myapp
// 检查数据完整性
db.test_restore.collection.count()
db.test_restore.collection.find().limit(10)
// 备份脚本示例(backup.sh)
#!/bin/bash
BACKUP_DIR="/backup/$(date +%Y%m%d)"
mkdir -p $BACKUP_DIR
# 执行备份
mongodump --db myapp --gzip --out $BACKUP_DIR
# 检查备份是否成功
if [ $? -eq 0 ]; then
echo "Backup successful: $BACKUP_DIR"
# 删除7天前的备份
find /backup -type d -mtime +7 -exec rm -rf {} \;
else
echo "Backup failed"
# 发送告警邮件
mail -s "MongoDB Backup Failed" admin@example.com <<< "Backup failed on $(date)"
fi
# 添加到crontab
# 0 0 * * * /path/to/backup.sh
// mongod.conf配置
auditLog:
destination: file
format: JSON
path: /var/log/mongodb/audit.log
logAppend: true
// 只审计认证和授权操作
db.setAuditConfig({
auditFilter: '{ "atype": { "$in": ["authenticate", "authorize"] } }'
})
// 监控认证失败
grep "authentication failed" /var/log/mongodb/mongod.log
// 监控连接尝试
grep "connection accepted" /var/log/mongodb/mongod.log
MongoDB提供了多种高级特性,支持大规模应用和复杂业务场景。以下是详细的高级特性讲解:
// 为集合启用分片
db.adminCommand({ enableSharding: "myapp" })
// 范围分片:使用userId作为分片键
db.adminCommand({ shardCollection: "myapp.users", key: { userId: 1 } })
// 哈希分片:使用userId的哈希值作为分片键
db.adminCommand({ shardCollection: "myapp.users", key: { userId: "hashed" } })
// 复合分片键:使用userId和createdAt
db.adminCommand({ shardCollection: "myapp.orders", key: { userId: 1, createdAt: 1 } })
// 启动配置服务器
mongod --configsvr --replSet cfgRS --dbpath /data/configdb --port 27019
// 初始化配置服务器副本集
mongo --port 27019
rs.initiate({
_id: "cfgRS",
configsvr: true,
members: [
{ _id: 0, host: "cfg1:27019" },
{ _id: 1, host: "cfg2:27019" },
{ _id: 2, host: "cfg3:27019" }
]
})
// 启动分片节点
mongod --shardsvr --replSet shard1RS --dbpath /data/shard1 --port 27018
// 初始化分片副本集
mongo --port 27018
rs.initiate({
_id: "shard1RS",
members: [
{ _id: 0, host: "shard1a:27018" },
{ _id: 1, host: "shard1b:27018" },
{ _id: 2, host: "shard1c:27018" }
]
})
// 启动mongos
mongos --configdb cfgRS/cfg1:27019,cfg2:27019,cfg3:27019 --port 27017
// 添加分片到集群
mongo --port 27017
sh.addShard("shard1RS/shard1a:27018,shard1b:27018,shard1c:27018")
sh.addShard("shard2RS/shard2a:27018,shard2b:27018,shard2c:27018")
// 查看集群状态
sh.status()
// 查看分片分布
sh.getBalancerState()
// 查看集合分片信息
db.collection.getShardDistribution()
// 启用平衡器
sh.startBalancer()
// 禁用平衡器
sh.stopBalancer()
// 设置平衡器窗口
sh.setBalancerState(true, { activeWindow: { start: "22:00", stop: "06:00" } })
// 启动事务
var session = db.getMongo().startSession()
var collection = session.getDatabase("myapp").getCollection("accounts")
try {
session.startTransaction()
// 执行操作
collection.updateOne({ _id: "A" }, { $inc: { balance: -100 } })
collection.updateOne({ _id: "B" }, { $inc: { balance: 100 } })
// 提交事务
session.commitTransaction()
print("Transaction committed successfully")
} catch (error) {
// 回滚事务
session.abortTransaction()
print("Transaction aborted:", error)
} finally {
session.endSession()
}
// 使用官方驱动
const { MongoClient } = require('mongodb');
async function transferFunds() {
const client = new MongoClient('mongodb://localhost:27017');
await client.connect();
const session = client.startSession();
const accountsCollection = client.db('myapp').collection('accounts');
try {
await session.withTransaction(async () => {
await accountsCollection.updateOne(
{ _id: 'A' },
{ $inc: { balance: -100 } },
{ session }
);
await accountsCollection.updateOne(
{ _id: 'B' },
{ $inc: { balance: 100 } },
{ session }
);
});
console.log('Transaction committed successfully');
} catch (error) {
console.error('Transaction aborted:', error);
} finally {
await session.endSession();
await client.close();
}
}
transferFunds();
// 使用Mongoose
const mongoose = require('mongoose');
async function transferFunds() {
const session = await mongoose.startSession();
try {
await session.withTransaction(async () => {
const Account = mongoose.model('Account');
await Account.updateOne(
{ _id: 'A' },
{ $inc: { balance: -100 } },
{ session }
);
await Account.updateOne(
{ _id: 'B' },
{ $inc: { balance: 100 } },
{ session }
);
});
console.log('Transaction committed successfully');
} catch (error) {
console.error('Transaction aborted:', error);
} finally {
await session.endSession();
}
}
transferFunds();
// 创建时间序列集合
db.createCollection("sensorData", {
timeseries: {
timeField: "timestamp", // 时间字段
metaField: "metadata", // 元数据字段(可选)
granularity: "seconds" // 时间粒度:seconds, minutes, hours
}
})
// 插入单个数据点
db.sensorData.insertOne({
timestamp: new Date(),
metadata: { sensorId: "sensor1", location: "room1" },
temperature: 22.5,
humidity: 60,
pressure: 1013
})
// 批量插入数据点
db.sensorData.insertMany([
{
timestamp: new Date(),
metadata: { sensorId: "sensor1", location: "room1" },
temperature: 22.5,
humidity: 60,
pressure: 1013
},
{
timestamp: new Date(Date.now() + 60000), // 1分钟后
metadata: { sensorId: "sensor1", location: "room1" },
temperature: 22.6,
humidity: 59,
pressure: 1012
}
])
// 按时间范围查询
db.sensorData.find({
timestamp: {
$gte: new Date(Date.now() - 24 * 60 * 60 * 1000), // 过去24小时
$lte: new Date()
},
"metadata.sensorId": "sensor1"
})
// 聚合查询:按小时统计平均值
db.sensorData.aggregate([
{
$match: {
timestamp: {
$gte: new Date(Date.now() - 24 * 60 * 60 * 1000),
$lte: new Date()
},
"metadata.sensorId": "sensor1"
}
},
{
$group: {
_id: {
$dateTrunc: {
date: "$timestamp",
unit: "hour"
}
},
avgTemperature: { $avg: "$temperature" },
avgHumidity: { $avg: "$humidity" }
}
},
{
$sort: { _id: 1 }
}
])
// 创建2dsphere索引(用于地理坐标)
db.places.createIndex({ location: "2dsphere" })
// 创建2d索引(用于平面坐标)
db.gameObjects.createIndex({ position: "2d" })
// 查找附近的地点(1000米内)
db.places.find({
location: {
$near: {
$geometry: {
type: "Point",
coordinates: [116.404, 39.915] // 北京坐标
},
$maxDistance: 1000
}
}
})
// 查找指定区域内的地点
db.places.find({
location: {
$geoWithin: {
$geometry: {
type: "Polygon",
coordinates: [[
[116.4, 39.9],
[116.5, 39.9],
[116.5, 40.0],
[116.4, 40.0],
[116.4, 39.9]
]]
}
}
}
})
// 创建全文索引
db.articles.createIndex({ title: "text", content: "text" })
// 创建带权重的全文索引
db.articles.createIndex(
{ title: "text", content: "text" },
{ weights: { title: 10, content: 1 } }
)
// 基本全文搜索
db.articles.find({ $text: { $search: "mongodb tutorial" } })
// 带排除词的搜索
db.articles.find({ $text: { $search: "mongodb -tutorial" } })
// 精确短语搜索
db.articles.find({ $text: { $search: '"mongodb tutorial"' } })
// 带分数排序
db.articles.find(
{ $text: { $search: "mongodb tutorial" } },
{ score: { $meta: "textScore" } }
).sort({ score: { $meta: "textScore" } })
// 监听集合变更
const changeStream = db.collection.watch()
// 处理变更
while (changeStream.hasNext()) {
const change = changeStream.next()
printjson(change)
// 根据操作类型处理
switch (change.operationType) {
case 'insert':
print('Document inserted:', change.fullDocument._id)
break
case 'update':
print('Document updated:', change.documentKey._id)
break
case 'delete':
print('Document deleted:', change.documentKey._id)
break
}
}
// 监听特定操作
db.collection.watch([
{ $match: { operationType: { $in: ['insert', 'update'] } } }
])
// 包含更新前数据(需要复制集)
db.collection.watch([], {
fullDocument: 'updateLookup'
})