36.总结
36.1 核心要点速览
SQL 和 NoSQL
对比维度 | SQL | NoSQL |
---|---|---|
数据模型 | - 表格(行×列) - 固定模式(Schema) |
- 文档(JSON/BSON)、键值、列族、图 - 动态模式,灵活 |
查询语言 | - 标准化 SQL - 支持复杂查询、聚合、联表 |
- 各自接口(如 MongoDB 查询、Redis GET) - 依赖具体实现 |
事务支持 | - 完整 ACID(原子性、一致性、隔离性、持久性) | - 通常“最终一致” - 部分产品支持限域事务 |
性能 | - 优化后复杂联表与事务性能优 - 适合结构化查询 |
- 高并发、低延迟 - 大规模水平扩展 |
适用场景 | - 金融、电商等高一致性需求 - 复杂关系建模 |
- 日志、社交、物联网等半/非结构化数据 - 高吞吐缓存 |
优势 | - 生态成熟、工具丰富 - 数据完整性高 |
- 扩展性强、灵活性高 - 支持多样数据模型 |
局限 | - 模式固定、扩展复杂 - 海量并发场景受限 |
- 标准化查询缺失 - 复杂事务与关联查询能力弱 |
NoSQL 类型对比
类型 | 代表工具 | 主要优点 | 主要缺点 |
---|---|---|---|
键值存储 | Redis、Memcached、DynamoDB | - 超高性能 - 简单模型 - 易水平扩展 |
- 仅键值对 - 无复杂查询 - 一致性风险 |
列式存储 | HBase、Cassandra、Bigtable | - 列级压缩高效 - OLAP 分析优 |
- 写入与更新慢 - 全表/多列查询低效 |
文档存储 | MongoDB、CouchDB、Couchbase | - 结构灵活 - 水平扩展 - 强查询功能 |
- 事务与一致性弱 - 复杂建模难 |
MongoDB下载安装
步骤
获取安装包
- 官方下载页获取 Community Edition
- 可选格式:
msi
(向导式安装)、zip
(便携解压)、Docker 镜像
安装流程
- 对于
msi
:一路“Next”完成 - 对于
zip
:解压后手动配置环境变量 - 对于 Docker:拉取镜像并运行容器
- 对于
服务运行账户
- Network Service user:Windows 内置低权限账户,安全风险最小
- Local User / Domain User:自定义账户,可精细控制文件与网络访问
- 仅影响操作系统层面权限,不改动数据库内部用户认证
可选组件
- MongoDB Compass:官方 GUI 可视化管理工具,命令行不熟悉者推荐
- 可根据需求勾选,无需强制安装
安装后验证
- 打开“服务”窗口,确认 “MongoDB” 服务存在且设为“自动”启动
安装选项对比表
安装环节 | 可选项 | 适用场景与说明 |
---|---|---|
安装包类型 | msi zip Docker |
向导安装 / 便携版 / 容器化部署 |
服务账户 | Network Service user Local/Domain User |
内置低权限 / 自定义权限,适合不同安全与企业环境需求 |
GUI 管理工具 | MongoDB Compass | 图形界面管理,适合不熟悉命令行的用户 |
安装验证 | Windows 服务管理 | 确认 “MongoDB” 服务已安装、启动类型为“自动” |
MongoDB配置文件
配置文件类型
mongod.cfg
(Windows 安装向导生成)mongod.conf
(Linux/macOS 原生,Windows 亦可)
文件格式对比
- Key-Value:安装程序生成,格式简单
- YAML:官方推荐,结构清晰,便于维护
常用配置项
- systemLog:日志路径与方式
- storage:数据目录与存储引擎
- net:绑定 IP 与端口
- security:开启授权认证
- processManagement:守护进程与 PID 文件
生效方式
- 配置文件:
mongod --config /path/to/mongod.conf
- 命令行:
--dbpath
,--logpath
,--bind_ip
,--port
,--auth
等
- 配置文件:
配置文件 | 默认平台 | 格式 | 适用场景 |
---|---|---|---|
mongod.cfg | Windows | Key-Value | 安装向导生成的简易配置 |
mongod.conf | Linux/macOS(*) | YAML | 官方推荐,易于扩展维护 |
配置项 | 作用 | 常见字段示例 |
---|---|---|
systemLog | 日志输出位置与模式 | destination , path |
storage | 数据目录与存储引擎选项 | dbPath |
net | 网络绑定地址与监听端口 | bindIp , port |
security | 用户认证与授权 | authorization: enabled |
processManagement | 守护进程模式与 PID 文件 | fork , pidFilePath |
MongoDB相关工具
官方工具
- mongosh:命令行交互,脚本与自动化管理
- Compass:GUI 可视化,拖拽式查询与分析
第三方工具示例
- Robo 3T / Studio 3T:增强型界面与导出功能
- DbGate:跨 DB 多引擎统一管理
CLI 使用流程
- 下载并解压或安装
- 启动工具后输入连接字符串
- 常用命令:
show dbs
、use <db>
、show collections
、db.collection.insertOne()
工具名称 | 类型 | 主要用途 |
---|---|---|
mongosh | CLI | 脚本化管理,自动化操作 |
Compass | GUI | 可视化数据浏览、查询与性能分析 |
Robo 3T | GUI | 轻量级图形界面,支持多种导出与插件 |
DbGate | GUI/多引擎 | 多数据库统一管理,支持自定义查询与插件安装 |
MongoDB连接和启用认证
连接字符串格式
mongodb://<user>:<pwd>@<host>:<port>/<db>?options
- 特殊字符需 URL 编码(
@ → %40
,/ → %2F
,: → %3A
,? → %3F
)
常用选项
- authSource、retryWrites、w、ssl、connectTimeoutMS、maxPoolSize…
启用认证步骤
- 在配置文件或启动参数中开启
authorization: enabled
或--auth
- 用命令行连接到 admin 库,
db.createUser(...)
创建管理员 - 优雅停服:
db.adminCommand({ shutdown: 1 })
或系统服务命令 - 重启带认证的服务,使用带凭证的连接字符串重新连接
- 在配置文件或启动参数中开启
步骤 | 方式 | 示例命令/字段 |
---|---|---|
开启认证 | 配置文件 / 参数 | security.authorization: enabled --auth |
创建管理员 | mongosh | use admin db.createUser({...}) |
优雅关闭 | mongosh / 系统服务 | db.adminCommand({ shutdown: 1 }) net stop MongoDB |
重启服务并连接 | 配置文件 / 参数 + URI | mongod --config ... mongodb://user:pwd@... |
MongoDB的ObjectID
定义与作用
- 默认主键类型,12 字节 BSON,用于全局唯一标识文档
- 十六进制字符串(24 字符)表现
组成结构
- 时间戳(4 字节):秒级 Unix 时间,保证排序性
- 机器标识(3 字节):主机唯一哈希,区分节点
- 进程 ID(2 字节):区分同机多进程生成
- 随机计数器(3 字节):同时间内递增,防止冲突
核心特性
- 全局唯一性:组合信息确保不同环境无重复
- 时间可提取:
getTimestamp()
可还原创建时刻 - 存储高效:仅 12 字节,比 UUID 更节省空间
常见用法
- 默认生成:插入文档时自动赋值
- 查询筛选:
find({ _id: ObjectId(...) })
- 手动生成:
var id = ObjectId()
- 获取创建时间:
ObjectId("…").getTimestamp()
组成部分 | 字节数 | 主要用途 |
---|---|---|
时间戳 | 4 | 保证生成顺序与时间关联 |
机器标识 | 3 | 区分不同主机 |
进程 ID | 2 | 区分同机不同进程 |
随机计数器 | 3 | 同秒内生成唯一性 |
MongoDB插入
insertOne(单条插入)
- 语法:
db.collection.insertOne(document, options)
- 自动生成
_id
(若未指定),或使用自定义_id
- 可选
writeConcern
、bypassDocumentValidation
等 - 返回
{ acknowledged: true, insertedId: <_id> }
- 语法:
insertMany(批量插入)
- 语法:
db.collection.insertMany([doc1, doc2, …], options)
- 一次插入多条文档
- 返回
{ acknowledged: true, insertedIds: […] }
- 语法:
冲突处理
- 若指定的
_id
已存在,抛出MongoServerError: E11000 duplicate key error
- 可在应用层捕获并处理,或改用
upsert
等方式
- 若指定的
insertOne vs. insertMany 对比
操作 | 场景 | 参数 | 返回值 | 注意事项 |
---|---|---|---|---|
insertOne | 单文档写入 | document , options |
{ acknowledged, insertedId } |
_id 自动/手动,冲突报错 |
insertMany | 批量写入 | Array<document> , options |
{ acknowledged, insertedIds } |
默认所有或全部失败(可配置) |
MongoDB查询
MongoDB基础查询
方法:
db.collection.find(query, projection)
常见操作:
- 等于
$eq
、不等$ne
、大于$gt
、小于$lt
、… - 字段存在
$exists
、类型匹配$type
- 等于
示例:
db.users.find({ age: { $gte: 25 } }, { name: 1 })
操作 | 语法 | 说明 |
---|---|---|
等于 | { age: 25 } |
age 精确匹配 25 |
范围查询 | { age: { $gt:25, $lt:30 } } |
age 在 (25,30) 之间 |
字段存在 | { score: { $exists:true } } |
仅返回含有 score 字段的 |
类型匹配 | { age: { $type:"int" } } |
age 必须为整数 |
MongoDB数组查询和嵌套字段查询
数组查询
$in
/$nin
:包含或不包含指定元素$elemMatch
:数组中元素级条件
嵌套字段
- 点语法
"bag.index":value
或范围查询{ "bag.index":{ $gt:0 }}
- 点语法
db.users.find({ lessons:{ $in:[1,4] } })
db.users.find({ "bag.index":1 })
功能 | 操作符 | 作用 |
---|---|---|
包含任一元素 | { lessons:{ $in:[…] }} |
数组含指定元素 |
排除某些元素 | { lessons:{ $nin:[…] }} |
数组不含指定元素 |
元素条件匹配 | { lessons:{ $elemMatch:{ $gt:2 }}} |
数组中存在大于 2 的元素 |
嵌套字段精确 | { "bag.index":1 } |
精确匹配子文档字段 |
MongoDB多条件查询
- AND(隐式):多个字段同级条件
- OR:
{ $or:[cond1,cond2] }
- 复合:AND +
$or
db.users.find({ age:25, $or:[{name:"T1"},{name:"T2"}] })
查询类型 | 语法 | 示例 |
---|---|---|
AND | { a:1, b:2 } |
同时满足 a=1 且 b=2 |
OR | { $or:[{a:1},{b:2}] } |
a=1 或 b=2 |
组合查询 | { c:3, $or:[…] } |
c=3 且 (a=1 或 b=2) |
MongoDB指定字段查询
- Projection:第二参数
{ field:1 }
包含,{ field:0 }
排除 - **默认返回
_id
**,可显式{ _id:0 }
- 支持嵌套字段:
{ "bag.index":1 }
db.users.find({}, { name:1, age:1, _id:0 })
方式 | 语法 | 说明 |
---|---|---|
包含字段 | { name:1, age:1 } |
仅返回 name 和 age |
排除字段 | { age:0 } |
返回所有字段但不包括 age |
排除 _id |
{ _id:0 } |
不返回 _id |
MongoDB模糊查询
- **正则
$regex
**:字符串模式匹配 - 忽略大小写:
$options:"i"
- 常用模式:
^
、$
、.
、*
、[]
、|
db.users.find({ name:{ $regex:"^T", $options:"i" } })
场景 | 语法 | 说明 |
---|---|---|
包含子串 | { name:{ $regex:"Ta" }} |
匹配包含 “Ta” |
开头匹配 | { name:{ $regex:"^T" }} |
以 T 开头 |
结尾匹配 | { name:{ $regex:"2$" }} |
以 2 结尾 |
忽略大小写 | { name:{ $regex:"t", $options:"i" }} |
不区分大小写 |
MongoDB排序查询
- **
.sort({ field:1|-1 })
**:1 升序,-1 降序 - 支持多字段:按字段顺序依次排序
db.users.find().sort({ age:1, name:-1 })
排序方式 | 语法 | 说明 |
---|---|---|
单字段升序 | { age:1 } |
age 从小到大 |
单字段降序 | { age:-1 } |
age 从大到小 |
多字段排序 | { age:1, name:-1 } |
age 再 name |
MongoDB分页查询
- **
skip(n).limit(m)
**:跳过 n,取 m 条 - 游标分页:
{ _id:{ $gt:lastId }}
+limit
- 排序分页:结合
.sort()
+ skip/limit
db.users.find().skip(10).limit(5)
db.users.find({ _id:{ $gt:objId } }).limit(5)
方法 | 优缺点 | 用例 |
---|---|---|
skip/limit | 简单;大量 skip 性能差 | 小数据量分页 |
游标分页 | 高效;依赖递增键;不支持随机页 | 大数据集连续翻页 |
排序分页 | 指定顺序,结合 skip/limit 使用 | 需按特定字段分页 |
MongoDB聚合查询概念
- Aggregation Pipeline:管道阶段数组
- 每阶段输入→处理→输出
- 典型阶段:
$match
,$group
,$sort
,$limit
,$project
MongoDB过滤文档聚合查询
- **
$match
**:在管道中做过滤 - 与
find
条件一致,但可与后续阶段组合
db.collection.aggregate([ { $match:{ age:{ $gt:25 } } } ])
操作符 | 用途 | 示例 |
---|---|---|
$match |
文档过滤 | { $match:{ status:"A" } } |
MongoDB分组聚合查询
- **
$group
**:类似 SQLGROUP BY
_id
定义分组键,可用聚合表达式计算- 常用累加器:
$sum
,$avg
,$max
,$min
,$push
,$addToSet
db.sales.aggregate([
{ $group:{ _id:"$item", total:{ $sum:"$quantity" } } }
])
累加器 | 功能 | 示例 |
---|---|---|
$sum |
求和 | { totalQty:{ $sum:"$qty" } } |
$avg |
平均值 | { avgPrice:{ $avg:"$price" } } |
$push |
收集为数组 | { allQty:{ $push:"$qty" } } |
MongoDB排序聚合查询
- **
$sort
**:管道内排序 - 用法同
.sort()
db.students.aggregate([ { $sort:{ score:-1, age:1 } } ])
排序符号 | 含义 |
---|---|
1 |
升序 |
-1 |
降序 |
MongoDB分页聚合查询
- **
$skip
+$limit
**:管道内分页 - 先
$sort
再跳过再限制
db.students.aggregate([
{ $sort:{ age:1 } },
{ $skip:5 },
{ $limit:5 }
])
阶段 | 描述 |
---|---|
$skip |
跳过指定文档数 |
$limit |
限制返回文档数 |
MongoDB索引
索引概念
- 用于加速查询,基于 B-tree 结构
- 全表扫描 → 索引查询:查找复杂度从 O(n) 降至 O(log n)
- 建立索引会增加存储空间和写入开销,需权衡查询性能与写入成本
单字段索引
- 针对单个字段创建升序(1)或降序(−1)索引
- 语法:
db.coll.createIndex({ field: 1 })
- 自动应用于
_id
字段,用户可自定义,如{ age: 1 }
- 支持覆盖索引:仅访问索引即可返回结果
复合索引
- 多字段组合索引,字段顺序决定前缀匹配能力
- 语法:
db.coll.createIndex({ a:1, b:-1 })
- 优化多字段查询与排序
- 只能利用最左前缀,如索引
{a,b,c}
能加速查询{a,…}
、{a,b,…}
与{a,b,c}
文本索引
- 全文搜索,跨多字段,用于
$text
查询 - 语法:
db.coll.createIndex({ title:"text", content:"text" })
- 支持短语搜索、排除词(
-word
)、相关性评分、权重设置 - 支持多语言与自定义停用词
哈希索引
- 基于字段值的哈希,适合等值查询
- 语法:
db.coll.createIndex({ key:"hashed" })
- 不支持范围查询或排序,只用于精确匹配
地理空间索引
- 2d:平面坐标(XY)索引;2dsphere:球面(经纬度)索引
- 语法:
db.coll.createIndex({ loc:"2dsphere" })
- 支持
$near
、$geoWithin
、$centerSphere
等地理查询
稀疏索引
- 仅索引包含该字段的文档,忽略字段缺失文档
- 语法:
db.coll.createIndex({ f:1 }, { sparse:true })
- 节省空间,适合字段偶尔存在场景
- 与唯一索引结合可对部分文档做唯一约束
唯一索引
- 保证索引字段值或字段组合唯一
- 语法:
db.coll.createIndex({ email:1 }, { unique:true })
- 防止重复数据,可在单字段或复合字段上应用
部分索引
- 基于
partialFilterExpression
只为符合条件的文档建索引 - 语法:
db.coll.createIndex({ f:1 }, { partialFilterExpression:{ status:"A" } })
- 更灵活替代稀疏索引,节省空间并优化特定查询
操作对比
索引类型 | 创建语法 | 适用场景 | 支持特点 | 限制 |
---|---|---|---|---|
单字段索引 | { field:1 } |
单字段查询、排序 | 覆盖索引 | 写入开销、所有文档均有索引条目 |
复合索引 | { a:1, b:-1 } |
多字段筛选与排序 | 前缀匹配 | 字段顺序敏感 |
文本索引 | { f:"text", g:"text" } |
全文搜索、短语、相关性排序 | 多字段、权重、多语言、停用词 | 字段类型限于字符串 |
哈希索引 | { field:"hashed" } |
精确值查询 | 等值查找高效 | 不支持范围/排序 |
地理空间索引 | { loc:"2d" } / { loc:"2dsphere" } |
位置搜索、地图应用 | 支持多种地理操作符 | 数据格式需 GeoJSON 或平面坐标 |
稀疏索引 | { f:1 }, { sparse:true } |
字段偶尔存在、减少无用索引条目 | 只索引存在字段的文档 | 不索引缺失字段文档 |
唯一索引 | { f:1 }, { unique:true } |
防止重复值 | 单字段或复合字段唯一性 | 创建前需清理重复数据 |
部分索引 | { f:1 }, { partialFilterExpression: {...} } |
特定条件优化 | 灵活过滤条件 | 仅对符合条件文档索引 |
MongoDB更新
首条更新 (updateOne
)
- 针对匹配的第一条文档执行更新
- 使用更新操作符:
$set
(设置/新增字段)、$inc
(增减数值)、$unset
(删除字段)等 - 支持
upsert:true
(无匹配时插入新文档) - 常见选项:
writeConcern
(写入确认)、collation
(排序规则)
多条更新 (updateMany
)
- 针对所有匹配文档批量执行更新
- 同样使用更新操作符,可组合多种如
$set
、$unset
、$inc
- 支持
upsert
、arrayFilters
(针对嵌套数组元素)、hint
(指定索引) - 适用于:批量状态修改、计数器更新、数据清理
替换更新 (replaceOne
)
- 用完整新文档替换匹配的第一条文档
- 替换文档必须包含所有必需字段(尤其是
_id
) - 不能使用
$
操作符,选项支持upsert
、collation
、writeConcern
- 适用于:需要保证文档结构一致、一次性覆盖所有字段的场景
操作对比
操作 | 更新范围 | 使用方式 | 文档保留 | 支持 Upsert | 覆盖方式 |
---|---|---|---|---|---|
updateOne | 第一条匹配文档 | 使用更新操作符(如 $set , $inc ) |
只改动指定字段 | 是 | 局部字段更新 |
updateMany | 所有匹配文档 | 同 updateOne |
只改动指定字段 | 是 | 局部字段更新 |
replaceOne | 第一条匹配文档 | 提供完整替换文档(无更新操作符) | 删除未包含字段 | 是 | 整个文档被新文档覆盖 |
MongoDB删除
deleteOne
- 删除匹配的第一条文档
- 语法:
db.collection.deleteOne(filter, { collation })
- 不返回被删文档
- 只会删除第一个符合条件的,操作不可撤销
deleteMany
- 删除所有匹配文档
- 语法:
db.collection.deleteMany(filter, { collation })
- 不返回被删文档
- 留空条件 (
{}
) 会清空整个集合
findOneAndDelete
- 查找并删除第一条匹配文档,同时返回它
- 语法:
db.collection.findOneAndDelete(filter, { sort, projection, collation })
- 返回被删文档,便于后续处理
- 可配合
sort
决定优先删除哪条
drop
- 删除整个集合及其索引
- 语法:
db.collection.drop()
- 一次性移除集合,无法恢复
remove (弃用)
- 旧版删除方法,不推荐
- 语法:
db.collection.remove(filter, { justOne })
- 功能已被
deleteOne
/deleteMany
取代
操作对比
操作 | 删除范围 | 返回被删文档 | 典型场景 |
---|---|---|---|
deleteOne | 第一条匹配文档 | 否 | 删除某个条件下的单条记录 |
deleteMany | 所有匹配文档 | 否 | 批量清理符合条件的数据 |
findOneAndDelete | 第一条匹配文档 | 是 | 删除并需要获取被删文档(审计/日志) |
drop | 整个集合 | 否 | 清理整个集合及其索引 |
remove (弃用) | 单条或多条(取决于 justOne ) |
否 | 旧版代码兼容,建议迁移至新 API |
MongoDB联动C#
C#操作MongoDB
驱动安装
- 推荐通过 NuGet 安装
MongoDB.Driver
,升级更便捷 - 也可从 GitHub 获取源代码,适合自定义需求
连接与模型
MongoClient("mongodb://…")
重用单例,线程安全GetDatabase
、GetCollection<T>
动态映射库与集合- C# 类加上
[BsonId]
、[BsonRepresentation]
、[BsonElement]
与字段一一对应
CRUD 操作
操作 | API | 说明 |
---|---|---|
插入 | InsertOne / InsertMany |
同步插入单个或多个文档 |
查询 | Find(filter).ToList() |
支持 Lambda 表达式和 Builders |
更新 | UpdateOne(filter, update) |
$set 、$inc 等操作符,支持 upsert |
替换 | ReplaceOne(filter, replacement) |
整文档替换 |
删除 | DeleteOne / DeleteMany |
精确条件删除单条或多条 |
索引 | Indexes.CreateOne(new CreateIndexModel…) |
为常用查询字段创建 B-Tree 索引 |
使用建议
- 为高频查询字段建索引
- 整个应用复用单个
MongoClient
- 捕获
MongoException
并记录,保证健壮性
C#使用Bson操作MongoDB
BSON 文档构建与插入
var doc = new BsonDocument { … }
支持嵌套BsonDocument
、BsonArray
collection.InsertOne(doc)
BSON 查询与筛选
var all = collection.Find(new BsonDocument()).ToList();
var filtered = collection.Find(new BsonDocument("age", new BsonDocument("$gt", 25))).ToList();
BSON 更新与删除
操作 | 调用示例 |
---|---|
更新 | collection.UpdateOne( new BsonDocument("name","John"), new BsonDocument("$set", new BsonDocument("age",35)) ) |
删除 | collection.DeleteOne( new BsonDocument("name","John") ) |
BSON 索引
collection.Indexes.CreateOne(new CreateIndexModel<BsonDocument>(new BsonDocument("name",1)));
要点
- 直接操作
BsonDocument
,更灵活但少了类型安全 - 适合动态结构或快速原型
- 与强类型 API 可混合使用,按需选择
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com