分布式NoSQL数据库——MongoDB

cuixiaogang

MongoDB 是一款基于分布式文件存储的NoSQL数据库系统,由 MongoDB Inc. 开发(现属于 MongoDB 公司),于 2009 年开源,旨在为海量非结构化数据提供高效、灵活的存储与查询解决方案。

基础

核心概念

  • 文档(Document):数据存储的基本单位,类似 JSON 格式,支持嵌套结构。与Mysql中的行对应。
  • 集合(Collection):一组文档的 集合,无固定模式。与Mysql中的表对应。
  • 数据库(Database):多个集合的逻辑分组,默认包含admin、local等系统库。与Mysql中的库对应。

优势

  • 灵活的 Schema:无需预先定义表结构,支持动态字段。
  • 高扩展性:通过分片(Sharding)实现水平扩展,支持 PB 级数据。
  • 高性能:内存映射存储引擎(WiredTiger)优化读写性能。

服务安装与配置

参考文档:

数据库操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- 显示数据库列表(注意,无集合的数据库不显示)
show dbs;

-- 显示当前正在使用的数据库
db;

-- 如果存在,则切换至数据库,如果不存在,创建后切换至数据库
use <dbname>;

-- 展示当前库中的集合列表
show tables;
show collections;

-- 删除当前数据库
db.dropDatabase();

集合操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-- 创建数据库 name:数据库名称 options:选项
db.cretaeCollection(name, options);
db.createCollection('collection_name', {capped: true, size : 100});

-- 更新集合名
-- renameCollection:要重命名的集合的完全限定名称(包括数据库名)。
-- to:目标集合的完全限定名称(包括数据库名)。
-- dropTarget(可选):布尔值。如果目标集合已经存在,是否删除目标集合。默认值为 false。
db.adminCommand({
renameCollection: "sourceDb.sourceCollection",
to: "targetDb.targetCollection",
dropTarget: <boolean>
})

-- 删除当前库的collection_name集合
db.collection_name.drop();
  • options
选项名 类型 默认值 生效版本 可使用的值 核心用途
capped 布尔值 false 1.0+ true(固定集合) / false(普通集合) 固定集合开关
size 数值 - 1.0+ 正整数(字节,需为 256 的倍数,如 1024(1KB)) 固定集合大小(字节)
max 数值 - 1.0+ 正整数(文档数量,如 1000) 固定集合最大文档数
validator 文档 - 2.2+ JSON Schema 文档(例:{ $jsonSchema: { bsonType: "object", ... } } 文档验证规则
validationLevel 字符串 moderate 3.2+ off(不验证) / moderate(仅验证新文档) / strict(验证所有文档) 验证级别
indexOptionDefaults 文档 {} 3.2+ 索引配置对象(例:{ expireAfterSeconds: 86400, sparse: true } 索引默认选项
timeseries 文档 - 4.2+ { timeField: "ts", metaField: "device", granularity: "seconds" } 时间序列集合配置
viewOn 字符串 - 5.0+ 现有集合名(如 “orders”) 创建视图
collation 文档 服务器默认 3.4+ 语言配置对象(例:{ locale: "zh_CN", strength: 2 } 语言排序规则
autoIndexId 布尔值 true 3.6+ true(自动创建 _id 索引) / false(手动管理) 自动创建 _id 索引

数据类型

分类 类型 支持版本 含义 典型场景 注意事项 / 示例
基础数据类型 String ≥ 1.0 UTF-8 字符串(BSON 最大 16MB) 用户名、描述 “hello world”
Integer (Int64) ≥ 2.2(默认) 64 位整数(±9e18) 年龄、用户 ID(如1234567890123) 2.2 前为 Int32(±2^31-1)
Boolean ≥ 1.0 布尔值 开关状态(is_active: true
Double ≥ 1.0 64 位浮点数 价格、经纬度(9.99/[116.40, 39.90]
Date ≥ 1.0 日期时间(Unix 毫秒时间戳) 创建时间(new Date("2025-04-14")
Null ≥ 1.0 显式空值(区别于字段不存在) 可选未设置字段(email: null db.col.find({ field: null }) 匹配null或字段不存在,需用$exists精确过滤
复合数据类型 Array ≥ 1.0 任意类型混合数组 标签、多值属性(["reading", 28]
Document ≥ 1.0 嵌套文档(支持深度嵌套) 地址({ addr: { city: "Beijing" } }
ObjectId ≥ 1.0 文档唯一 ID(12 字节,含时间戳 + 机器 ID) 主键(_id默认类型) 自动生成含时间戳,按时间插入可优化索引
Map ≥ 5.0 键值对映射(优化动态字段查询) 配置参数({ "key1": "value1" } 查询需引号包裹键名({ "map.key": "value" }
特殊数据类型 Regex ≥ 1.0 PCRE 正则表达式 邮箱格式校验(/^\\w+@\\w+\\.com$/ 谨慎使用,可能导致全表扫描
DBPointer ≥ 1.0(弃用 跨集合文档引用(如{ $ref: "users", $id: ObjectId("...") } 历史系统跨集合关联 3.6+ 推荐$lookup聚合替代
MinKey/MaxKey ≥ 1.0 范围查询边界占位符 索引优化({ age: { $lt: MaxKey } } 仅用于查询,不可存储为文档值
二进制/高精度 Binary Data ≥ 1.0 二进制数据(如图片、文件) 存储缩略图(BinData(0, "base64...")
UUID ≥ 3.4 全局唯一 ID(binary subtype 4) 设备 ID(UUID("123e4567-e89b...") 需驱动支持(如 Python bson.uuid.UUID
Decimal128 ≥ 2.6(稳定≥3.4) 高精度十进制(避免浮点误差) 金融金额(Decimal128("1000.01") 2.6-3.4 为实验性,需显式声明$decimal128
已弃用类型 Symbol ≤ 3.6(废弃 早期字符串类型(用于系统集合) 迁移为String
Code ≤ 4.4(废弃 存储 JavaScript 代码 安全风险高,改用应用层逻辑

文档操作

插入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- 插入单条
db.collection.insertOne(document, options);
db.users.insertOne({
username: "user1",
email: "user1@example.com",
created_at: new Date()
});

-- 插入多条
db.collection.insertMany(documents, options);
db.users.insertMany([
{ username: "user2", email: "user2@example.com" },
{ username: "user3", email: "user3@example.com" }
]);
  • options
选项名 类型 默认值 可使用值范围 生效版本 核心用途(关键差异) 适用方法
writeConcern 文档/字符串 实例默认值 w: 0//“majority”, wtimeout(毫秒) 3.2+ 共有:insertOne 单文档确认;insertMany 整体/部分确认(依赖 ordered) 共有
bypassDocumentValidation 布尔 false true(跳过集合验证) 3.2+ 共有:两方法均跳过 validator 校验(谨慎使用) 共有
session 事务会话对象 null 有效的事务会话(ClientSession 实例) 4.0+ 共有:insertMany 支持事务内原子化批量操作 共有
comment 字符串 / 文档 null 任意可序列化值(如{ tag: "bulk" } 4.4+ 共有:标注操作(审计 / 监控可见) 共有
let 文档 {} 变量绑定(如 { today: ISODate() } 5.0+ 共有:供 collation 或表达式使用 共有
ordered 布尔 true true(按序插入,失败即停) / false(并行插入,忽略部分错误) 2.6+ insertMany 特有:控制批量插入的顺序性与错误策略(insertOne 无此概念) insertMany
maxDocs 数值 0 正整数(分片集群限制单次插入文档数,如 10000) 5.0+ insertMany 特有:防止超大批次导致分片压力(insertOne 固定为 1 条) insertMany
continueOnError 布尔 false (已废弃,改用 ordered: false) 3.2-4.2 insertMany 特有(旧):旧版兼容选项,新版通过 ordered: false 实现 insertMany

更新

1
2
3
4
5
6
7
8
9
10
11
12
13
-- 单条更新
db.collection.updateOne(filter, update, options);
db.users.updateOne(
{ username: "user1" },
{ $set: { status: "inactive" }, $inc: { points: 10 } }
);

-- 批量更新
db.collection.updateMany(filter, update, options)
db.users.updateMany(
{ role: "admin" },
{ $set: { permissions: ["read", "write"] } }
);
  • options
选项名 类型 默认值 可使用值范围 生效版本 核心用途(关键差异) 适用方法
writeConcern 文档 / 字符串 实例默认值 w: 0//“majority”, wtimeout(毫秒) 3.2+ 共有:updateOne 单文档确认;updateMany 批量确认(受 arrayFilters 影响) 共有
bypassDocumentValidation 布尔 false true(跳过集合验证) 3.2+ 共有:跳过更新后的文档校验(如临时修改敏感字段) 共有
session 事务会话对象 null 有效的事务会话(ClientSession 实例) 4.0+ 共有:updateMany 支持事务内批量原子操作(如批量扣减库存) 共有
comment 字符串 / 文档 null 任意可序列化值(如{ tag: "bulk_update" } 4.4+ 共有:标注操作(审计 / 监控可见,如 “promotion_price”) 共有
let 文档 {} 变量绑定(如 { discount: 0.8 },供更新表达式使用) 5.0+ 共有:临时变量在 update 表达式中复用(如$expr: { $gte: ["$price", "$$discount"] } 共有
upsert 布尔 false true(不存在则插入) / false 2.6+ 共有:updateOne 插入单文档;updateMany 按条件插入多条(慎用!可能批量创建) 共有
arrayFilters 数组 [] 过滤数组元素的条件(如[{ "elem.status": "active" }] 3.6+ updateMany 特有:批量更新数组内元素,精准控制更新目标 updateMany
hint 文档 / 字符串 null 索引键或名称(如 { user_id: 1 },分片键索引优先) 3.2+ 共有:updateMany 强制使用索引优化批量操作(避免全表扫描) 共有
collation 文档 服务器默认 语言排序规则(如{ locale: "zh", strength: 2 } 3.4+ 共有:影响字符串比较(如 $eq、$gt),updateMany 批量应用相同规则 共有

删除

1
2
3
4
5
6
7
8
9
10
11
-- 删除单条
db.collection.deleteOne(filter, options);
db.users.deleteOne({ username: "user1" });

-- 删除所有
db.collection.deleteMany(filter, options);
db.users.deleteMany({ status: "deleted" });

-- 查找并删除单个文档
db.collection.findOneAndDelete(filter, options);
db.users.findOneAndDelete({ status: "deleted" });
  • options
选项名 类型 默认值 可使用值范围 生效版本 核心用途(关键差异) 适用方法
writeConcern 文档 / 字符串 实例默认值 w: 0//“majority”, wtimeout(毫秒) 3.2+ 共有:deleteOne 单文档确认;deleteMany 批量确认;findOneAndDelete 事务内确认 共有
session 事务会话对象 null 有效的事务会话(ClientSession 实例) 4.0+ 共有:findOneAndDelete 支持事务内原子化查询 + 删除 共有
comment 字符串 / 文档 null 任意可序列化值(如{ tag: "cleanup" }) 4.4+ 共有:标注操作(如 “delete_old_logs”) 共有
collation 文档 服务器默认 语言排序规则(如{ locale: "zh", strength: 2 }) 3.4+ 共有:影响查询条件的字符串比较(如 deleteOne 按拼音匹配删除) 共有
hint 文档 / 字符串 null 索引键或名称(如{ user_id: 1 },分片键索引优先) 3.2+ 共有:findOneAndDelete 强制索引优化查询路径;deleteMany 避免全表扫描 共有
maxTimeMS 数值 0(无限制) 正整数(毫秒,如 5000) 3.2+ 共有:防止长时间运行(findOneAndDelete 常见于复杂查询场景) 共有
returnDocument 字符串 “before” “before”(删除前文档) / “after”(删除后文档,仅空文档) 3.2+ findOneAndDelete 特有:控制返回数据(deleteOne 无返回,deleteMany 批量无意义) findOneAndDelete
sort 文档 {} 排序键(如 { created_at: -1 } 3.2+ findOneAndDelete 特有:指定删除优先级(如删除最新文档) findOneAndDelete
projection 文档 {} 字段投影(如{ username: 1, _id: 0 } 3.2+ findOneAndDelete 特有:控制返回文档的字段(deleteOne/deleteMany 无返回) findOneAndDelete
let 文档 {} 变量绑定(如{ expire: ISODate("2025-01-01") } 5.0+ 共有:供查询条件中的$expr使用(如 deleteMany 按变量过滤) 共有

文档简单查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- 查询多条
-- query:用于查找文档的查询条件。默认为 {},即匹配所有文档。
-- projection(可选):指定返回结果中包含或排除的字段。
db.collection.find(query, projection);
db.users.find({ username: "user1" });
db.users.find({ age: { $gt: 30 }, status: "active" });
db.users.find({ active: true }, { username: 1, email: 1 });

-- 排序:1表示升序,-1表示降序
-- skip() 和 limit() 方法通常用于配合使用,以实现分页查询。但是在大型数据集上使用 skip() 可能会导致性能问题,因为 MongoDB 在执行查询时需要扫描并跳过指定数量的文档,因此建议仅在需要时才使用 skip() 方法,尽量避免在大型数据集上连续使用。
-- 当结合 skip() 和 limit() 时,skip() 应该在 limit() 之前使用,以避免意外行为。
db.collection.find().sort({field1:1,field2:-1}).skip(<skip>).limit(<limit>);

-- 查询单条
db.collection.findOne(query, projection);

高级语法

过滤条件

1
2
3
4
5
-- 查询中的query,更新和删除中的filter,可以使用查询运算符来实现更复杂的查询逻辑
db.collection.find(query, projection);
db.collection.deleteOne(filter, options);
db.collection.updateOne(filter, update, options);
db.col.find({"likes": {$gt:50}, $or: [{"by": "test"},{"title": "教程"}]}).pretty();
  • 查询运算符(find/delete/update 过滤条件)
分类 运算符 语法示例 核心用途 生效版本
基础比较 $eq { age: { $eq: 30 } } 等于(可省略,直接 { age: 30 } 1.0+
$ne { status: { $ne: "closed" } } 不等于 1.0+
$gt/$gte { score: { $gt: 80 } } 大于 / 大于等于 1.0+
$lt/$lte { price: { $lte: 100 } } 小于 / 小于等于 1.0+
范围查询 $in { category: { $in: ["A", "B"] } } 字段值在数组中 1.0+
$nin { tags: { $nin: ["spam"] } } 字段值不在数组中 1.0+
逻辑组合 $and { $and: [{ age: { $gt: 18 } }, { status: "active" }] } 多条件同时满足(可省略,直接逗号分隔) 1.0+
$or { $or: [{ age: { $lt: 13 } }, { age: { $gt: 65 } }] } 任一条件满足 1.0+
$not { email: { $not: /@example\.com/ } } 取反(支持正则 / 表达式) 2.2+
类型检查 $type { field: { $type: "string" } } 检查字段类型(”string”/“objectId” 等,或数字代码如 2 表示字符串) 2.2+
正则匹配 $regex { username: { $regex: "^user" } } 正则表达式匹配(支持i不区分大小写,m多行) 1.0+
存在性 $exists { email: { $exists: true } } 字段存在(true 存在,false 不存在) 1.0+

更新操作

1
2
3
4
5
6
-- 更新时,update可以使用更多的操作符管理文档内容 
db.collection.updateOne(filter, update, options);
db.collection.updateOne(
{ name: "Alice" },
{ $set: { age: 26 }, $addToSet: { habits: ""}, $push: { like: "ball" } }
);
  • 更新运算符(updateOne/updateMany 操作)
分类 运算符 语法示例 核心用途 生效版本
赋值 $set { $set: { "profile.name": "Alice" } } 设置字段值(支持嵌套路径) 1.0+
$unset { $unset: { "profile.age": "" } } 删除字段(值可为任意非空,通常用 “”) 1.0+
增减 $inc { $inc: { balance: -100 } } 数值增减(支持负数,原子操作) 1.0+
数组 $push { $push: { tags: "new_tag" } } 向数组添加元素(支持 $each 批量添加,$position 指定位置) 1.0+
$pull { $pull: { tags: "old_tag" } } 从数组删除匹配元素(按值删除) 1.0+
$addToSet { $addToSet: { tags: "unique_tag" } } 数组去重添加(仅新增不存在的元素) 2.2+
条件更新 $min/$max { $min: { low_score: 60 } } 仅当新值更小时更新($min)/ 更大时更新($max) 2.6+
表达式 $expr { $set: { discount: { $expr: { $multiply: ["$price", 0.8] } } } } 内联表达式(需配合 let 变量) 3.6+

聚合查询

管道在Unix和Linux中一般用于将当前命令的输出结果作为下一个命令的参数。
MongoDB的聚合管道将MongoDB文档在一个管道处理完毕后将结果传递给下一个管道处理。管道操作是可以重复的。
表达式:处理输入文档并输出。表达式是无状态的,只能用于计算当前聚合管道的文档,不能处理其它的文档。

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
-- 聚合查询
db.collection.aggregate([
{管道1: {表达式1}},
{管道2: {表达式2}},
{管道3: {表达式3}}
]);
db.articles.aggregate([
{ $match : { score : { $gt : 70, $lte : 90 } } },
{ $group: { _id: null, count: { $sum: 1 } } }
]);

-- $group分组查询(特殊一些,需要_id指定分组key)
db.collection_name.aggregate(
{$group:
{
_id : '$字段名', //根据某个字段进行分组 group by field
别名 : {聚合函数:'$字段名'} //计算的数据
}
}
);

-- 分组查询年龄之和
db.collection_name.aggregate(
{$group: {
_id:'$name',
'total_age':{$sum:'$age'}
}}
);

-- _id 为null代表不分组
db.collection_name.aggregate(
{$group: {
_id:null,
"平均年龄":{$avg:'$age'},
"数据条数":{$sum:1}
}}
);

-- $push 进行拼接操作
db.collection_name.aggregate(
{$group: {
_id : '$sex',
'count' : {$sum:1},
"名单" : {$push:'$name'}
}}
);

-- $first $last 按照分组排序获取第一、最后的数据
db.collection_name.aggregate({
$group:{
_id:'$sex',
"小组第一个人":{$first:'$name'},
"小组最后一个人":{$last:'$name'}
}
});

-- 年龄大于30的数据 $match 过滤数据
db.collection_name.aggregate({
$match:{"age":{$gt:30}}
});

-- 对过滤后的数据进行分组
db.collection_name.aggregate([
{$match:{"age":{$gt:30}}},
{$group:{_id:null, 'count':{$sum:1}}}
]);

-- 限定字段的管道符 $project(//1 显示 0 不显示)
db.collection_name.aggregate({
$project:{"_id":0, "name":1,"sex":0,"age":1}
});

-- 排序 $sort(按年龄从小到大)
db.collection_name.aggregate({
$sort: {
"age":1
}
});

-- 限制输出 $limit $skip
db.collection_name.aggregate([
{$sort:{"age":1}},
{$limit:10},
{$skip:10}
]);

-- 数组进行拆分 $unwind
-- 只针对数组有作用,拆分后,1条数据将会变为数组个数的数据条数
db.users.aggregate([
{$match:{"data":{$exists:true}}},
{$unwind:"$data"}
]);
  • 聚合运算符(aggregate 管道)

| 分类 | 运算符 | 语法示例 | 核心用途 | 生效版本 |
|—|—|—|—|—|—|
| 文档操作 | $project | { $project: { name: 1, _id: 0 } } | 投影字段(1 包含,0 排除) | 1.5+ |
| | $match | { $match: { status: "active" } } | 过滤文档(等价于 find 的条件) | 1.5+ |
| 分组统计 | $group | { $group: { _id: "$category", total: { $sum: 1 } } } | 按字段分组,聚合计算($sum/$avg/$first 等) | 1.5+ |
| 数组处理 | $unwind | { $unwind: "$hobbies" } | 展开数组为单独文档(path 字段名,preserveNullAndEmptyArrays 控制空数组) | 2.2+ |
| 排序分页 | $sort | { $sort: { created_at: -1 } } | 排序(1 升序,-1 降序) | 1.5+ |
| | $limit | { $limit: 10 } | 限制结果数量 | 1.5+ |
| 表达式 | $lookup | { $lookup: { from: "orders", localField: "user_id", foreignField: "user_id", as: "user_orders" } } | 左外连接(类似 SQL JOIN) | 3.2+ |

其他运算符

运算符 语法示例 核心用途 生效版本
$all { tags: { $all: ["tech", "guide"] } } 数组包含所有元素(顺序无关) 1.3+
$elemMatch { scores: { $elemMatch: { $gte: 80, $lt: 90 } } } 数组中存在至少一个元素满足条件 2.2+
$size { tags: { $size: 5 } } 数组长度等于指定值 3.2+
$[] { $set: { "array.$[id].status": "done" } },配合 arrayFilters 批量更新数组指定元素(需 updateMany) 3.6+
$geoNear { $geoNear: { near: [lon, lat], distanceField: "dist" } } 聚合管道中查找附近文档(需索引) 2.4+
$geoWithin { location: { $geoWithin: { $center: [[lon, lat], 1000] } } } 文档在圆形 / 多边形范围内 2.4+
$near { location: { $near: [lon, lat], $maxDistance: 1000 } } 查询附近文档(find 方法,需 2d 索引) 2.2+
$eval { $eval: "function() { return db.collection.find().limit(1); }" } 执行 JS 代码(不推荐,4.4+ 需开启 allowEvaluate) 1.0+
$jsonSchema { $jsonSchema: { bsonType: "object", required: ["email"] } } 文档验证(createCollection 的 validator 选项) 3.2+
$lookup 见聚合运算符部分 - -

索引管理

索引分类

在 MongoDB 中,常见的索引类型包括:

  • 单字段索引:基于单个字段的索引。
  • 复合索引:基于多个字段组合的索引。
  • 文本索引:用于支持全文搜索。
  • 地理空间索引:用于地理空间数据的查询。
  • 哈希索引:用于对字段值进行哈希处理的索引。

索引操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-- 创建索引
-- keys:一个对象,指定了字段名和索引的排序方向(1 表示升序,-1 表示降序)。
-- options:一个可选参数,可以包含索引的额外选项。
db.collection.createIndex(keys, options);
-- 创建 age 字段的升序索引
db.myCollection.createIndex({ age: 1 });
-- 创建 name 字段的文本索引
db.myCollection.createIndex({ name: "text" });
-- 创建hash索引
db.collection.createIndex( { field: "hashed" } );

-- 删除索引
db.collection.dropIndex( "indexName" );

-- 删除所有索引
db.collection.dropIndexes();
  • 创建索引时的options
Option Key 支持版本 含义 可选值 / 类型 使用场景
background ≥ 2.6 后台创建索引(不阻塞读写) true/false(默认false) 生产环境避免锁表(如用户量百万级集合创建索引)
unique ≥ 2.0 确保字段值唯一 true/false 用户邮箱、身份证号等唯一标识字段(需配合sparse忽略缺失值)
name ≥ 2.0 自定义索引名称 字符串(默认自动生成) 复杂索引管理(如user_age_status_idx便于运维排查)
sparse ≥ 2.2 仅索引存在的字段(忽略缺失值) true/false 可选字段(如用户last_login_time,非必填时节省 50%+ 索引空间)
expireAfterSeconds ≥ 2.2 TTL 索引(自动过期文档) 数字(≥0,秒) 日志、缓存类数据(如用户会话记录,设置 24 小时过期)
partialFilterExpression ≥ 3.2 部分索引(仅包含符合条件的文档) MongoDB 查询表达式 高频查询子集(如status: “active”的订单,索引大小减少 70%)
collation ≥ 3.4 自定义排序规则(语言 / 大小写 / 重音) Collation 对象 多语言场景(如中法双语系统的name字段排序)
hidden ≥ 5.0 隐藏索引(不被优化器自动使用) true/false 测试新索引性能(需手动hint(),避免干扰现有查询)
2dsphere ≥ 2.4 地理空间索引(经纬度) 配置对象(如sphereVersion) 位置服务(如附近的餐厅搜索,需loc字段为[经度, 纬度]数组)
textIndexVersion ≥ 3.2 文本索引版本(提升分词能力) 1或2(默认1) 复杂搜索(如电商商品description字段,version 2支持短语高亮)
weights ≥ 2.6 文本索引字段权重(影响相关性) 对象(字段:权重) 内容平台(如文章title权重 3,content权重 1,优先匹配标题)
default_language ≥ 2.6 文本索引默认语言(分词规则) 语言代码(如”chinese”) 非英语场景(中文需额外安装cjk分词器,否则默认按拼音分词)
writeConcern ≥ 2.6 索引创建时的写入一致性 WriteConcern 对象 金融场景(如w: “majority”确保多数节点确认,避免索引不一致)
dropDups ≤ 3.0 已弃用:删除重复文档创建唯一索引(改用unique: true) true/false 无(3.0 + 强制报错,直接使用unique)
storageEngine ≤ 3.4 已弃用:指定索引存储引擎(3.4 + 统一 WiredTiger) 字符串(如”mmapv1”) 无(新版本忽略)

数据库安全

  • 首先以无密码形式登录
  • 创建管理员密码,use admin;
  • 添加一个超级管理员db.createUser({user:"admin",pwd:"password",roles:["root"]});
  • 验证密码(必须在admin库下才能正常执行)db.auth('admin', 'password');
  • 重启mongodb服务(不单单只是重启,如果安装了windows的服务,需要重新安装windows服务)
  • 关闭mongo服务,然后重新启动mongod --dbpath "d:\mongodb\db\" --logpath "d:\mongo\log\mongo.log" --auth
  • 注意的点:
    • 如果安装了MongoDB的windows服务,需要先卸载windows服务
    • 需要确定windows服务的名称是否为mongodb
1
2
3
4
5
6
net stop mongodb
sc delete mongodb
//注意,开启了验证用户身份(--auth)匿名用户仍然可以登录,但是不能查询、操作任何数据。
mongod --dbpath "d:\mongodb\db\" --logpath "d:\mongo\log\mongo.log" --install --serviceName "MongoDB" --auth
//为某个库添加指定的管理员,添加的管理员只能访问某个库
db.createUser({user:"root",pwd:"root", roles:[role:"dbOwner", db:"db_name"]});

常用组件

副本集

什么是副本集

MongoDB副本集是将数据同步在多个服务器的过程。
副本集提供了数据的冗余备份,并在多个服务器上存储数据副本,提高了数据的可用性, 并可以保证数据的安全性。
副本集还允许您从硬件故障和服务中断中恢复数据。

副本集结构图

副本集的特征

  • N 个节点的集群
  • 任何节点可作为主节点
  • 所有写入操作都在主节点上
  • 自动故障转移
  • 自动恢复

如何设置副本集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 启动副本集的mongo服务
mongod --port "PORT" --dbpath "YOUR_DB_DATA_PATH" --replSet "REPLICA_SET_INSTANCE_NAME"
# 示例
mongod --port 27017 --dbpath "D:\set up\mongodb\data" --replSet rs0

# 连接上mongo客户端,执行以下命令
# 启动一个新的副本集
rs.initiate();
# 查看副本集配置
rs.conf();
# 查看副本集状态
rs.status();
# 添加副本集成员(其他节点上执行)
rs.add(HOST_NAME:PORT)
rs.add("mongod1.net:27017")

Mongos(分片路由进程)

在Mongodb里面存在另一种集群,就是分片技术,可以满足MongoDB数据量大量增长的需求。
当MongoDB存储海量的数据时,一台机器可能不足以存储数据,也可能不足以提供可接受的读写吞吐量。这时,我们就可以通过在多台机器上分割数据,使得数据库系统能存储和处理更多的数据。

分片结构图

图中主要有如下所述三个主要组件:

  • Shard:
    用于存储实际的数据块,实际生产环境中一个shard server角色可由几台机器组个一个replica set承担,防止主机单点故障
  • Config Server:
    mongod实例,存储了整个 ClusterMetadata,其中包括 chunk信息。
  • Query Routers:
    前端路由,客户端由此接入,且让整个集群看上去像单一数据库,前端应用可以透明使用。

为什么使用分片

  • 复制所有的写入操作到主节点
  • 延迟的敏感数据会在主节点查询
  • 单个副本集限制在12个节点
  • 当请求量巨大时会出现内存不足。
  • 本地磁盘不足
  • 垂直扩展价格昂贵

如何设置Mongos

分片结构端口分布如下:

1
2
3
4
5
6
Shard Server 1:27020
Shard Server 2:27021
Shard Server 3:27022
Shard Server 4:27023
Config Server :27100
Route Process:40000
  • 启动Shard Server
1
2
3
4
5
6
7
8
[root@100 /]# mkdir -p /www/mongoDB/shard/s0
[root@100 /]# mkdir -p /www/mongoDB/shard/s1
[root@100 /]# mkdir -p /www/mongoDB/shard/s2
[root@100 /]# mkdir -p /www/mongoDB/shard/s3
[root@100 /]# mkdir -p /www/mongoDB/shard/log
[root@100 /]# /usr/local/mongoDB/bin/mongod --port 27020 --dbpath=/www/mongoDB/shard/s0 --logpath=/www/mongoDB/shard/log/s0.log --logappend --fork
....
[root@100 /]# /usr/local/mongoDB/bin/mongod --port 27023 --dbpath=/www/mongoDB/shard/s3 --logpath=/www/mongoDB/shard/log/s3.log --logappend --fork
  • 启动Config Server
1
2
[root@100 /]# mkdir -p /www/mongoDB/shard/config
[root@100 /]# /usr/local/mongoDB/bin/mongod --port 27100 --dbpath=/www/mongoDB/shard/config --logpath=/www/mongoDB/shard/log/config.log --logappend --fork
  • 启动Route Process
1
/usr/local/mongoDB/bin/mongos --port 40000 --configdb localhost:27100 --fork --logpath=/www/mongoDB/shard/log/route.log --chunkSize 500
  • 配置Sharding
1
2
3
4
5
6
7
8
9
10
11
12
[root@100 shard]# /usr/local/mongoDB/bin/mongo admin --port 40000
MongoDB shell version: 2.0.7
connecting to: 127.0.0.1:40000/admin
mongos> db.runCommand({ addshard:"localhost:27020" })
{ "shardAdded" : "shard0000", "ok" : 1 }
......
mongos> db.runCommand({ addshard:"localhost:27029" })
{ "shardAdded" : "shard0009", "ok" : 1 }
mongos> db.runCommand({ enablesharding:"test" }) #设置分片存储的数据库
{ "ok" : 1 }
mongos> db.runCommand({ shardcollection: "test.log", key: { id:1,time:1}})
{ "collectionsharded" : "test.log", "ok" : 1 }
  • 程序代码内无需太大更改,直接按照连接普通的mongo数据库那样,将数据库连接接入接口40000