目录
1 准备工作... 5
1.1 相关网址... 6
1.1 下载安装... 6
1.1.1 下载:... 6
1.1.2 安装:... 7
1.2 其他工具... 17
1.2.1 robomongo. 17
1.2.2 示例代码... 19
2 基础知识... 20
2.1 数据库... 20
2.2 集合... 20
2.2.1 固定集合:... 20
2.3 文档... 21
3 mongo Shell 22
4 CRUD操作... 26
4.1 插入并保存... 26
4.1.1 id 字段... 26
4.1.2 插入操作... 26
4.2 查询... 29
4.2.1 常规查询... 29
4.2.2 内嵌文档查询... 31
4.2.3 数组的查询... 32
4.3 更新... 34
4.4 删除... 34
5 索引... 34
5.1 执行计划:... 35
5.2 单索引... 37
5.3 复合索引... 38
5.4 $操作符如何使用索引... 39
5.4.1 低效率的操作符... 39
5.4.2 索引对象和数组... 39
5.4.3 索引基数... 40
5.5 何时不应该使用索引... 40
5.6 索引类型... 41
5.6.1 唯一索引... 41
5.6.2 稀疏索引... 41
5.6.3 全文索引... 42
6 聚合... 45
6.1 聚合框架... 45
6.1.1 $project操作... 46
6.1.2 $match. 47
6.1.3 $group. 47
6.1.4 $sort. 48
6.1.5 综合应用... 48
6.1.6 $unwind. 49
6.2 聚合命令... 50
6.2.1 count. 50
6.2.2 distinct. 50
7 GirdFS. 51
8 用户管理... 55
9 创建副本集... 55
9.1 MongoDB Atlas. 56
10 复制集(replication)... 63
10.1 搭建复制集... 63
10.1.1 直接命令启动... 63
10.1.2 配置文件启动... 76
10.1.3 配置复制集:... 88
10.1.4 安装为windows 服务 的集群... 99
10.2 复制集的验证... 113
10.2.1 数据同步... 113
10.2.2 主从故障切换... 119
10.3 复制集群工作原理... 125
11 分片(Sharding)... 126
11.1 什么是分片集群... 126
11.2 什么时候分片... 127
11.3 分片集群的组件... 127
11.4 分片集群中的数据分散方式... 130
11.4.1 数据库分片... 132
11.4.2 集合分片... 133
11.5 搭建分片集群... 135
11.5.1 启动 mongod 和 configserver. 135
11.5.2 配置复制集:... 140
11.5.3 启动 mongos. 152
11.5.4 配置分片集群... 154
11.5.5 对数据库和集合进行分片... 158
11.6 分片集群的查询和索引... 185
12 其它... 185
1 准备工作
资源网址、下载安装、辅助工具
1.1 相关网址
官网:
https://www.mongodb.com/
下载:
https://www.mongodb.com/download-center
驱动:
https://docs.mongodb.com/ecosystem/drivers/csharp/
中文社区:
http://www.mongoing.com/
1.1
1.1 下载安装
1.1.1 下载:
https://www.mongodb.com/download-center
https://www.mongodb.com/download-center/community
下载老是让你注册账号,有没登录界面,点击左侧栏跳转到所以版本下载地址,如下图所示:
跳转到如下地址,选择要安装的版本:
https://www.mongodb.org/dl/win32/x86_64-2008plus-ssl?_ga=2.86137437.439937506.1541555987-1693515396.1540462101
1.1.2 安装:
安装文档:
https://docs.mongodb.com/manual/installation/
1.1.2.1 使用msi安装包安装为windows服务:
https://docs.mongodb.com/manual/tutorial/install-mongodb-enterprise-on-windows/
这里我们选择使用 msi 安装,并且选择 安装为windows服务方式启动。
安装完成后,默认端口是27017
配置文件:
运行 mongod -remove 会删除名为“MongoDb”的windows服务,其它名字的MongoDb 的windows服务不会被删除
如果不小心 运行了 mongod --remove 删除了该windows 服务
可运行如下命名,重新安装
mongod --config "C:\Program Files\MongoDB\Server\4.0\bin\mongod.cfg" --install --serviceName "MongodDb" --serviceDisplayName "MongodDb Service" --serviceDescription "MongodDb Data Service"
删除 具体的 windows 服务 还是在 cmd 界面中使用如下命令进行删除:
sc delete 服务名称
1.1.2.2 手动安装安装为Windows Service
下载二进制文件:
https://www.mongodb.org/dl/win32/x86_64-2008plus-ssl?_ga=2.254700552.1864371647.1543196577-1693515396.1540462101
选择一个版本下载,比如:
win32/mongodb-win32-x86_64-2008plus-ssl-v4.0-latest.zip
解压到一个文件夹,这里是:
F:\mongodb\mongo-windowsserver\bin
在bin文件文件夹中添加配置文件:mongod.cfg,内容如下:
# mongod.conf
# for documentation of all options, see:
# http://docs.mongodb.org/manual/reference/configuration-options/
# Where and how to store data.
storage:
dbPath: F:\mongodb\mongo-windowsserver\data
journal:
enabled: true
# engine:
# mmapv1:
# wiredTiger:
# where to write logging data.
systemLog:
destination: file
logAppend: true
path: F:\mongodb\mongo-windowsserver\log\mongod.log
# network interfaces
net:
port: 27050
bindIp: 127.0.0.1
#processManagement:
#security:
#authorization:enabled
#operationProfiling:
#replication:
#sharding:
## Enterprise-Only Options:
#auditLog:
#snmp:
打开cmd界面,
输入如下命令,以根据配置文件,将MongoDb安装为windows服务
mongod --config F:\mongodb\mongo-windowsserver\bin\mongod.cfg --install --serviceName "MongoDb-Service-27050" --serviceDisplayName "MongoDb-27050"
参数说明可通过输入 mongod -h 查看:
查看MongoDb window服务:
将其启动并设置启动方式为“自动”
查看日志文件:
1.2 其他工具
1.2.1 robomongo
下载地址:https://robomongo.org/download
连接MongoDb
1.2.2 示例代码
git clone https://keasy5.visualstudio.com/MongoDb.JumpStart/_git/MongoDb.JumpStart
2 基础知识
2.1 数据库
默认有三个数据库名的数据库:
2.2 集合
集合就是一组文档,可以看作是一个拥有动态模式的表
2.2.1 固定集合:
创建一个固定集合,
db.createCollection("cappedColl", {"capped":true, "size":1024, max:5})
for(i=0; i<10; i++){
db. cappedColl.insert(
{
"i":i,
"username": "user" + i,
"age":Math.floor(Math.random() * 120),
"created":new Date()
}
);
}
db.getCollection('cappedColl').find({})
2.3 文档
文档是MongoDB中数据的基本单元, 类似于关系型数据库中的行。
3 mongo Shell
mongo shell 是MongoDB的客户端管理工具,可以在shell中使用命令与MongoDB的实例进行交互,对数据库的管理操作(CRUD,集群配置,状态查看等)。
设置系统环境变量:
PATH 环境变量追加:
C:\Program Files\MongoDB\Server\4.0\bin
mongo
简单使用常用命名:
l help
l 显示数据库: show dbs
l 切换为当前数据库:use testDb
l 显示当前数据库:db
l 显示数据库操作命令:db.help()
l 显示数据库集合:show collections
l 查询集合:
db.getCollection('User').find({})
db.getCollection('User').find()
db.User.find()
db. User.find({"Name":{"$all":["Kevin"]}}).pretty();
l 插入数据:
插入一条:db.User.insertOne({"Name": "Test1"})
db.User.insertOne({"Name": "Test2", "Age": 10})
插入多条:
db.User.insertMany([{"Name": "Test3"},{"Name":"Test4"}, {"Name":"Test5","Age":25}])
l 查找:
插入一条: db.User.find({"Name":"Test01"})
l 更新
db.collection.updateOne(<filter>, <update>, <options>)
db.collection.updateMany(<filter>, <update>, <options>)
db.collection.replaceOne(<filter>, <update>, <options>)
更新一条
db.User.updateOne({"Name":"Test2"},{$set:{Name:"Test2-2"});
更新多条:
db.User.insertOne({"Name": "Test6", "Age": 28})
db.User.find({Age: {$gte:25}}).pretty()
更新多条并且满足年龄大于20:
db.User.updateMany({"Age":{$gte:25}}, {$set:{"Age":29}})
db.User.find ({"Age":{$gte:29}})
db.User.updateOne({"Age":{$gte:29}}, {$set:{"Age":30}})
l 删除
db.collection.deleteMany()
db.collection.deleteOne()
db.User.deleteOne ({"Age":{$gte:29}})
db.User.deleteMany ({"Age":{$gte:29}})
4 CRUD操作
4.1 插入并保存
db.collection.insertOne()
db.collection.insertMany()
db.collection.insert()
4.1.1 id 字段
在MongoDB中,存储于集合中的每一个文档都需要一个唯一的 _id 字段作为 primary_key。如果一个插入文档操作遗漏了``_id`` 字段,MongoDB驱动会自动为``_id``字段生成一个 ObjectId。
4.1.2 插入操作
db.users.insertOne(
{
name: "sue",
age: 19,
status: "P"
}
)
db.users.insertMany(
[
{ name: "bob", age: 42, status: "A", },
{ name: "ahn", age: 22, status: "A", },
{ name: "xi", age: 34, status: "D", }
]
)
db.users.insert(
{
name: "sue2",
age: 19,
status: "P"
})
db.users.insertMany(
[
{ name: "bob2", age: 42, status: "A", },
{ name: "ahn2", age: 22, status: "A", },
{ name: "xi2", age: 34, status: "D", }
]
)
4.2 查询
4.2.1 常规查询
示例演示:
数据:
db.inventory.insertMany([
{ item: "journal", qty: 25, size: { h: 14, w: 21, uom: "cm" }, status: "A" },
{ item: "notebook", qty: 50, size: { h: 8.5, w: 11, uom: "in" }, status: "A" },
{ item: "paper", qty: 100, size: { h: 8.5, w: 11, uom: "in" }, status: "D" },
{ item: "planner", qty: 75, size: { h: 22.85, w: 30, uom: "cm" }, status: "D" },
{ item: "postcard", qty: 45, size: { h: 10, w: 15.25, uom: "cm" }, status: "A" }
]);
查询说明 |
Mongo shell命令 |
C# |
查询所有
|
db.inventory.find( {} )
|
|
查询status="D"
|
db.inventory.find( { status: "D" } )
|
var filter = Builders<BsonDocument>.Filter.Eq("status", "D"); var result = collection.Find(filter).ToList();
|
查询status="A" or status="D"
|
db.inventory.find( { status: { $in: [ "A", "D" ] } } ) |
var filter = Builders<BsonDocument>.Filter.In("status", new[] { "A", "D" }); var result = collection.Find(filter).ToList(); |
status = "A" AND qty < 30
|
db.inventory.find( { status:"A", qty:{$lt:30} } ) |
var builder = Builders<BsonDocument>.Filter; var filter = builder.And(builder.Eq("status", "A"), builder.Lt("qty", 30)); var result = collection.Find(filter).ToList(); |
status = "A" OR qty < 30
|
db.inventory.find( { $or:[ {status:"A"}, {qty:{$lt:30}} ] })
|
var builder = Builders<BsonDocument>.Filter; var filter = builder.Or(builder.Eq("status", "A"), builder.Lt("qty", 30)); var result = collection.Find(filter).ToList(); |
status = "A" AND ( qty < 30 OR item LIKE "p%")
|
db.inventory.find( { status:"A", $or:[ {qty:{$lt:30}}, {item: /^p/} ] } ) |
var builder = Builders<BsonDocument>.Filter; var filter = builder.And( builder.Eq("status", "A"), builder.Or(builder.Lt("qty", 30), builder.Regex("item", new BsonRegularExpression("^p")))); var result = collection.Find(filter).ToList(); |
|
|
|
注意:
操作符:
https://docs.mongodb.com/manual/reference/operator/query/
4.2.2 内嵌文档查询
查询说明 |
Mongo shell命令 |
C# |
内嵌对象精确查询 |
db.inventory.find( { size: { h: 14, w: 21, uom: "cm" } } ) |
var filter = Builders<BsonDocument>.Filter.Eq("size", new BsonDocument { { "h", 14 }, { "w", 21 }, { "uom", "cm" } }); var result = collection.Find(filter).ToList(); |
查询 |
db.inventory.find({ "size.uom":"in" })
|
var filter = Builders<BsonDocument>.Filter.Eq("size.uom", "in"); var result = collection.Find(filter).ToList(); |
size.h < 5
|
db.inventory.find( { "size.h":{$lt:15} } ) |
var filter = Builders<BsonDocument>.Filter.Lt("size.h", 15); var result = collection.Find(filter).ToList(); |
the nested field h is less than 15, the nested field uom equals "in", and the status field equals "D" |
db.inventory.find( { "size.h":{$lt:15}, "size.uom":"in", "status":"D" } ) |
var builder = Builders<BsonDocument>.Filter; var filter = builder.And(builder.Lt("size.h", 15), builder.Eq("size.uom", "in"), builder.Eq("status", "D")); var result = collection.Find(filter).ToList(); |
|
|
|
|
|
|
|
|
|
4.2.3 数组的查询
演示数据
db.inventory.insertMany([
{ item: "journal", qty: 25, tags: ["blank", "red"], dim_cm: [ 14, 21 ] },
{ item: "notebook", qty: 50, tags: ["red", "blank"], dim_cm: [ 14, 21 ] },
{ item: "paper", qty: 100, tags: ["red", "blank", "plain"], dim_cm: [ 14, 21 ] },
{ item: "planner", qty: 75, tags: ["blank", "red"], dim_cm: [ 22.85, 30 ] },
{ item: "postcard", qty: 45, tags: ["blue"], dim_cm: [ 10, 15.25 ] }
]);
查询说明 |
Mongo shell命令 |
C# |
where the field tags value is an array with exactly two elements, "red" and "blank", in the specified order:
等于
|
db.getCollection('inventory').find( {tags:["red", "blank"]} ) |
var filter = Builders<BsonDocument>.Filter.Eq("tags", new[] { "red", "blank" }); var result = collection.Find(filter).ToList(); |
find an array that contains both the elements "red" and "blank"
都包含
|
db.getCollection('inventory').find( {tags: {$all: ["red", "blank"]}} )
等同于
db.articles.find( { $and: [ { tags: [ "ssl", "security" ] } ] } )
|
var filter = Builders<BsonDocument>.Filter.All("tags", new[] { "red", "blank" }); var result = collection.Find(filter).ToList(); |
数组中 存在 15<dim_cm <20 的数组元素 排除了元素:
|
db.inventory.find( { dim_cm: { $gt: 15, $lt: 20 } } ) |
var builder = Builders<BsonDocument>.Filter; var filter = builder.And(builder.Gt("dim_cm", 15), builder.Lt("dim_cm", 20)); var result = collection.Find(filter).ToList();
|
|
|
|
|
|
|
|
|
|
|
|
|
4.3 更新
4.4 删除
5 索引
for(i=0; i<1000; i++){
db.users.insert(
{
"i":i,
"username": "user" + i,
"age":Math.floor(Math.random() * 120),
"created":new Date()
}
);
}
5.1 执行计划:
https://blog.csdn.net/u012702547/article/details/80606614
http://www.mongoing.com/eshu_explain1
http://blog.51cto.com/1937519/2301699?source=dra
执行计划分析:
执行计划的三种模式:
queryPlanner :默认
executionStats :会返回最佳执行计划的一些统计信息
allPlansExecution :用来获取所有执行计划
queryPlanner返回值说明:
参数 |
含义 |
plannerVersion |
查询计划版本 |
namespace |
要查询的集合 |
indexFilterSet |
是否使用索引 |
parsedQuery |
查询条件, |
winningPlan |
最佳执行计划 |
stage |
查询方式,常见的有COLLSCAN/全表扫描、IXSCAN/索引扫描、FETCH/根据索引去检索文档、SHARD_MERGE/合并分片结果、IDHACK/针对_id进行查询 |
filter |
过滤条件 |
direction |
搜索方向 |
rejectedPlans |
拒绝的执行计划 |
serverInfo |
MongoDB服务器信息 |
executionStats 返回值说明:
参数 |
含义 |
plannerVersion |
查询计划版本 |
namespace |
要查询的集合 |
indexFilterSet |
是否使用索引 |
parsedQuery |
查询条件, |
winningPlan |
最佳执行计划 |
stage |
查询方式,常见的有COLLSCAN/全表扫描、IXSCAN/索引扫描、FETCH/根据索引去检索文档、SHARD_MERGE/合并分片结果、IDHACK/针对_id进行查询 |
filter |
过滤条件 |
direction |
搜索方向 |
rejectedPlans |
拒绝的执行计划 |
serverInfo |
MongoDB服务器信息 |
executionStats参数,含义如下:
参数 |
含义 |
executionSuccess |
是否执行成功 |
nReturned |
返回的结果数 |
executionTimeMillis |
执行耗时 |
totalKeysExamined |
索引扫描次数 |
totalDocsExamined |
文档扫描次数 |
executionStages |
这个分类下描述执行的状态 |
stage |
扫描方式,具体可选值与上文的相同 |
nReturned |
查询结果数量 |
executionTimeMillisEstimate |
预估耗时 |
works |
工作单元数,一个查询会分解成小的工作单元 |
advanced |
优先返回的结果数 |
docsExamined |
文档检查数目,与totalDocsExamined一致 |
5.2 单索引
创建索引:
db.users.createIndex({username:1})
db.getCollection('users').find({username:"user2500000"}).hint({$natural: 1}).explain()
db.getCollection('users').find({username:"user2500000"}).explain("queryPlanner")
db.getCollection('users').find({username:"user2500000"}).explain("executionStats")
db.getCollection('users').find({username:"user2500000"}).explain("allPlansExecution")
db.getCollection('users').find({username:"user2500000"}).sort({"username":-1}).explain("executionStats")
5.3 复合索引
db.users.createIndex({"age":1,"username":1})
db.users.find({"age":{"$gte":21, "$lte":30}}).sort({"username":1}).limit(10000).explain("executionStats")
db.getCollection('users').find({"age":{"$gte":100}}).count(100)
db.getCollection('users').find({"age":{"$gte":100}}).limit(100).explain("executionStats")
db.getCollection('users').find({"age":{"$gte":100}}).skip(10000000).limit(20).explain("executionStats")
db.getCollection('users').find({"age":{"$gte":100}}).sort({"created":-1}).skip(10000000).limit(20).explain("executionStats")
- 选择键的方向:
相互反转(在每个方向都乘以 -1)的索引都等价的:
{"age":1 , "username": -1} 等价于 {"age":-1 , "username": 1}
- 2. 隐式索引(前缀索引)
索引{"age":1 , "username": 1}可以当做索引{"age":1}使用
5.4 $操作符如何使用索引
5.4.1 低效率的操作符
{"indexKey ":{"$exists":true}}
$ne
$not
$nin 总是使用全表扫描
2. 范围
3. OR 查询
实际上是执行两次查询,然后结果集合并, 能同时使用两个索引,
db.users.find({"$or":[{"age":100}, {"$gt":"user5", "$lt":"user8"}]}).explain("executionStats")
5.4.2 索引对象和数组
- 索引嵌套文档
db.collection.createIndex("a.b": 1)
起作用:
db.collection.find({"a":{"b":xx}})
不起作用:
db.collection.find("a.b":"xxx")
- 索引数组
db.collection.createIndex("a.arrData": 1)
3. 多建索引
对于某个索引的键,如果这个键在某个文档中是一个数组,那么这个索引就会标记为多键索引。
被标记为多键索引,就无法变成非多键索引。非法删除这个字段为数组的所有文档并且重建索引
多键索引可能会比非多键索引满,并且多个索引条目指向同一个文档,返回结果必须去重操作
5.4.3 索引基数
集合中某个字段拥有不同值的数量。
一个字段的基数越高,这个键的索引就越有用
在基数高的键上建立索引。
把基数高的键放在复合索引的前面
5.5 何时不应该使用索引
结果集在原集合中所占的比例越大,索引的速度就越慢。
因为使用索引需要进行两次查找:一次是查找索引条目,一次是根据索引指针去查找相应的文档。
一般来说, 如果查询返回的集合内30%的文档(或者更多),那就应该对索引和全表扫描的速度进行比较
5.6 索引类型
5.6.1 唯一索引
比如比较熟悉的“_id”索引。
该索引建重复,插入会抛出异常
db.user2.createIndex({"username":1},{"unique":true})
5.6.2 稀疏索引
唯一索引把null看做值,无法将多个缺少唯一索引中的键的文档插入集合。
稀疏索引,唯一索引知对包含相应的键的文档生效。当一个字段存在时,它必须是唯一的。
唯一稀疏索引:
db.user2.createIndex("{"age":1}",{"unique":true, "sparse":true})
非唯一稀疏索引
db.user2.createIndex("{"age":1}",{ "sparse":true})
如果某个文档不包含 age字段,使用稀疏索引不会返回该文档
5.6.3 全文索引
https://docs.mongodb.com/manual/tutorial/text-search-in-aggregation/
如同内置了多语言分词机制
在一个操作频繁的集合上创建全文本检索可能回到导致MongoDB过载,应该是离线状态下创建全文检索。
创建全文检索可能会导致内存不够用。
测试数据:
db.textIndexTest.insert({author:"杜甫",title:"绝句",article:"两个黄鹂鸣翠柳, 一行白鹭上青天。窗含西岭千秋雪,门泊东吴万里船。"})
db.textIndexTest.insert({author:"李白",title:"静夜思",article:"床前明月光,疑是地上霜。 举头望明月,低头思故乡。"})
db.textIndexTest.insert({author:"张 王",title:"你好",article:"测试数据"})
db.textIndexTest.insert({author:"李贺",title:"李凭箜篌引",article:"吴丝蜀桐张高秋,空山凝云颓不流。 江娥啼竹素女愁,李凭中国弹箜篌。 昆山玉碎凤凰叫,芙蓉泣露香兰笑。 十二门前融冷光,二十三丝动紫皇。 女娲炼石补天处,石破天惊逗秋雨。 梦入神山教神妪,老鱼跳波瘦蛟舞。 吴质不眠倚桂树,露脚斜飞湿寒兔。"})
创建全文检索:
db.textIndexTest.createIndex( { author: "text", description: "text" } )
db.textIndexTest.find({$text:{$search:"杜甫"}})
db.textIndexTest.find({$text:{"$search":"空山凝云颓不流"}})
db.textIndexTest.dropIndex("author_text_description_text");
db.textIndexTest.createIndex( { author: "text", article: "text" } )
db.textIndexTest.find({$text:{"$search":"空山凝云颓"}}) #无结果
db.textIndexTest.find({$text:{"$search":"空山凝云颓不流"}})
db.textIndexTest.find({$text:{$search:"王"}})
MongoDB中文全文索引建立方式与英文的简历几乎相同 是根据词(英文单词)的方式建立的。
如果一个值里面有多个值 则需要按空格方式隔开,”张 王” 系统则认为是两个词。
感觉MongodB的中文全文索引沒有想象中的强大。想要实现中文模糊搜素
可以用elasticsearch或者Sphinx,或者lucene
设置语言:
https://docs.mongodb.com/manual/reference/text-search-languages/#text-search-languages
db.articles.find(
{ $text: { $search: "leche", $language: "es" } }
)
一个集合只能创建一个全文索引
db.articles.createIndex( { subject: "text" } )
db.articles.insert(
[
{ _id: 1, subject: "coffee", author: "xyz", views: 50 },
{ _id: 2, subject: "Coffee Shopping", author: "efg", views: 5 },
{ _id: 3, subject: "Baking a cake", author: "abc", views: 90 },
{ _id: 4, subject: "baking", author: "xyz", views: 100 },
{ _id: 5, subject: "Café Con Leche", author: "abc", views: 200 },
{ _id: 6, subject: "Сырники", author: "jkl", views: 80 },
{ _id: 7, subject: "coffee and cream", author: "efg", views: 10 },
{ _id: 8, subject: "Cafe con Leche", author: "xyz", views: 10 }
]
)
db.articles.find( { $text: { $search: "coffee" } } )
# the phrase coffee shop
db.articles.find( { $text: { $search: "\"coffee shop\"" } } )
#contain the words coffee but do not contain the term shop
db.articles.find( { $text: { $search: "coffee -shop" } } )
db.articles.find( { $text: { $search: "coffee" } } ).explain("executionStats")
db.articles.createIndex({author:"text"})
db.articles.dropIndex("subject_text")
db.articles.createIndex({author:"text"})
db.articles.find( { $text: { $search: "coffee" } } )
db.articles.find( { $text: { $search: "xyz" } } )
6 聚合
6.1 聚合框架
for(i=0; i<1000; i++){
db.users2.insert(
{
"i":i,
"username": "user" + i,
"age":Math.floor(Math.random() * 120),
"created":new Date()
}
);
}
6.1.1 $project操作
利用$project 实现投影操作,相当于SQL中的 Select 子句
db.users2.aggregate([
{"$project":{
"username":1
}
}
])
db.users2.aggregate([
{"$project":{
"_id":0,
"username":1
}
}
])
db.users2.aggregate([
{"$project":{
"username":1,
"age":1 ,
"是否大于93": {"$gt":["$age",93]}
}
}
])
6.1.2 $match
db.users2.aggregate([
{"$match":{"age": {"$gt":93} }
}
])
6.1.3 $group
分组操作, 相当于SQL 中的 Group By 子句
db.users2.aggregate([{
"$group":{
"_id":"$age",
"age_count":{"$sum":1}
}
}
]) .explain("executionStats")
6.1.4 $sort
排序操作
db.users2.aggregate([
{"$project":{
"username":1,
"age":1 }
}, {
"$sort":{"age" : -1, "username":1}
}
])
6.1.5 综合应用
db.users2.aggregate([
{"$match":{"age":{"$gte":93, "$lte":115}}},
{"$project":{
"username":1,
"age":1
}
},
{"$group":{
"_id":"$age",
"age_count":{"$sum":1},
"usersData":{"$push":"$username"}
}
},
{
"$sort":{"age_count" : -1}
},
{"$skip":10},
{"$limit":10}
])
6.1.6 $unwind
将数组中的每一个值拆分为单独的文档
db.depts.insert({"name":"移动产品部", "bussiness":["研发", "开发", "维护"]})
db.depts.insert({"name":"财务部", "bussiness":["发工资", "财务预算"]})
db.depts.find({})
db.depts.aggregate([
{"$unwind":"$bussiness"}
])
db.depts.aggregate([
{"$unwind":"$bussiness"},
{"$match":{"bussiness": "发工资"}}
])
6.2 聚合命令
6.2.1 count
db.users.count()
db.users.count({"age":100})
6.2.2 distinct
db.runCommand({
"distinct":"users2",
"key":"age"
})
7 GirdFS
MongoDB里面支持大数据的存储,例如:图片,音乐,二进制数据,需要用户自己处理:
使用 mongofiles , 有三个基本操作;
put :将文件上传到GridFS
list: 列出GridFS中的文件
get:下载
命名
exit -- 退出mongo命名
mongofiles --help
在文件所在的文件夹中执行:
mongofiles put moon.png
上传
mongofiles put
查询
use test
show collections
db.fs.files.find().pretty()
文档分片存储
db.fs.chunks.find({}, {"_id":1, "n":1,"files_id":1}).pretty()
下载:
mongofiles get moon.png
删除
mongofiles delete moon.png
mongofiles list
8 用户管理
https://docs.mongodb.com/manual/reference/built-in-roles/#built-in-roles
9 创建副本集
使用复制,将数据副本保存到多台服务器上。
副本集是一组服务器,其中有一个主服务器(Primary),用于处理 客户端请求,
多个备份服务器(secondary),用于保存主服务器的数据副本
主服务器崩溃,备份服务器会自动将其中一个成员升级为新的主服务器
https://docs.mongodb.com/manual/replication/
配置文件:
https://docs.mongodb.com/manual/reference/configuration-file-settings-command-line-options-mapping/#conf-file-command-line-mapping
https://blog.csdn.net/yamadeee/article/details/79746154
9.1 MongoDB Atlas
注册
登录
https://docs.atlas.mongodb.com/
正在创建集群
10 复制集(replication)
10.1 搭建复制集
参考:
https://blog.csdn.net/huanyuminhao/article/details/82052107
10.1.1 直接命令启动
mongod --replSet mg-cluster0 --dbpath F:\mongodb\cluster0\node1 --port 27100
mongod --replSet mg-cluster0 --dbpath F:\mongodb\cluster0\node2 --port 27101
mongod --replSet mg-cluster0 --dbpath F:\mongodb\cluster0\node3 --port 27102
集群名称:mg-cluster0
新打开一个cmd界面,输入
mongo --port 27100
rs.initiate()
查看配置
rs.conf()
向主节点添加从节点和仲裁节点
rs.add("localhost:27101")
rs.addArb("localhost:27102")
查看主节点状态(详细信息)
rs.status()
获取复制集的简要信息:
db.isMaster()
10.1.2 配置文件启动
配置文件说明;
https://docs.mongodb.com/manual/reference/configuration-options/
replication Options:
https://docs.mongodb.com/manual/reference/configuration-options/#replication-options
示例集群:mg-cluster1
创建3个数据库文件
在F:\mongodb\cluster1\node1 添加配置文件 mongod.cfg :
# mongod.conf
# for documentation of all options, see:
# http://docs.mongodb.org/manual/reference/configuration-options/
# Where and how to store data.
storage:
dbPath: F:\mongodb\cluster1\data\node1
journal:
enabled: true
# engine:
# mmapv1:
# wiredTiger:
# where to write logging data.
systemLog:
destination: file
logAppend: true
path: F:\mongodb\cluster1\log\node1.log
# network interfaces
net:
port: 27201
bindIp: 127.0.0.1
#processManagement:
#security:
#authorization:enabled
#operationProfiling:
replication:
#oplogSizeMB: <int>
replSetName: mg-cluster1
#secondaryIndexPrefetch: <string>
#enableMajorityReadConcern: <boolean>
#sharding:
## Enterprise-Only Options:
#auditLog:
#snmp:logappend=true
在F:\mongodb\cluster1\node2 添加配置文件 mongod.cfg :
# mongod.conf
# for documentation of all options, see:
# http://docs.mongodb.org/manual/reference/configuration-options/
# Where and how to store data.
storage:
dbPath: F:\mongodb\cluster1\data\node1
journal:
enabled: true
# engine:
# mmapv1:
# wiredTiger:
# where to write logging data.
systemLog:
destination: file
logAppend: true
path: F:\mongodb\cluster1\log\node1.log
# network interfaces
net:
port: 27201
bindIp: 127.0.0.1
#processManagement:
#security:
#authorization:enabled
#operationProfiling:
replication:
#oplogSizeMB: <int>
replSetName: mg-cluster1
#secondaryIndexPrefetch: <string>
#enableMajorityReadConcern: <boolean>
#sharding:
## Enterprise-Only Options:
#auditLog:
#snmp:
在F:\mongodb\cluster1\node3 添加配置文件 mongod.cfg :
# mongod.conf
# for documentation of all options, see:
# http://docs.mongodb.org/manual/reference/configuration-options/
# Where and how to store data.
storage:
dbPath: F:\mongodb\cluster1\data\node1
journal:
enabled: true
# engine:
# mmapv1:
# wiredTiger:
# where to write logging data.
systemLog:
destination: file
logAppend: true
path: F:\mongodb\cluster1\log\node1.log
# network interfaces
net:
port: 27201
bindIp: 127.0.0.1
#processManagement:
#security:
#authorization:enabled
#operationProfiling:
replication:
#oplogSizeMB: <int>
replSetName: mg-cluster1
#secondaryIndexPrefetch: <string>
#enableMajorityReadConcern: <boolean>
#sharding:
## Enterprise-Only Options:
#auditLog:
#snmp:
分别启动:
mongod --config F:\mongodb\cluster1\node1\bin\mongod.cfg
mongod --config F:\mongodb\cluster1\node2\bin\mongod.cfg
mongod --config F:\mongodb\cluster1\node3\bin\mongod.cfg
测试是否链接成功:
mongo --port 27201
特别注意:
如下图启动服务失败,是因为没有创建相应的文件夹(配置文件中的数据文件夹和日志文件),
请手动创建如下文件夹:
data
data\node1 、data\node2 data\node3
log
启动成功后,数据文件和日志文件创建成功
10.1.3 配置复制集:
新打开一个cmd 界面:
连接到27201 节点
mongo --port 27201
rs.status()
rs.initiate()
再此查看状态:
rs.status()
查看配置
rs.conf()
向主节点添加从节点
rs.add("localhost:27202")
向主节点添加仲裁节点
rs.addArb("localhost:27203")
再此查看状态:
rs.status()
10.1.4 安装为windows 服务 的集群
具体如何手动安装为windows 服务 参见章节:手动安装安装为Windows Service
mongod --config "F:\mongodb\cluster-service\node1\bin\mongod.cfg" --install --serviceName "MongoDbService-Cluster-01" --serviceDisplayName "MongoDb-Cluster-01"
mongod --config "F:\mongodb\cluster-service\node2\bin\mongod.cfg" --install --serviceName "MongoDbService-Cluster-02" --serviceDisplayName "MongoDb-Cluster-02"
mongod --config "F:\mongodb\cluster-service\node3\bin\mongod.cfg" --install --serviceName "MongoDbService-Cluster-03" --serviceDisplayName "MongoDb-Cluster-03"
安装完成,日志如下:
2018-11-28T10:02:16.147+0800 I CONTROL [main] Trying to install Windows service 'MongoDbService-Cluster-01'
2018-11-28T10:02:16.621+0800 I CONTROL [main] Service 'MongoDbService-Cluster-01' (MongoDb-Cluster-01) installed with command line 'F:\mongodb\cluster-service\node1\bin\mongod.exe --config F:\mongodb\cluster-service\node1\bin\mongod.cfg --service'
2018-11-28T10:02:16.621+0800 I CONTROL [main] Service can be started from the command line with 'net start MongoDbService-Cluster-01'
生成数据相关文件:
分别手动启动这个三个windows 服务
复制集 的配置 如上章节: 配置复制集:
打开 cmd
mongo "127.0.0.1:27301"
查看状态 rs.status()
初始化集群
rs.initiate()
再此查看状态:
rs.status()
查看配置
rs.conf()
向主节点添加从节点
rs.add("127.0.0.1:27302")
向主节点添加仲裁节点
rs.addArb("127.0.0.1:27303")
再此查看状态:
rs.status()
简单的验证配置是否成功:
在 27301 的服务上执行:
use test
db.createCollection("testCollection")
db.testCollection.insert({"name":"test_insert_node1"})
db.testCollection.find()
10.2 复制集的验证
10.2.1 数据同步
主节点:负责数据的读写操作,
从节点:只负责读取。
仲裁节点:不负责数据的存储。
验证方法,
向主节点插入一个集合,
观察从节点和仲裁节点是否存在 向主节点插入的集合。
在主节点数据库命令窗口执行以下命令
执行前:
use test
db.createCollection("testCollection")
执行后:
主节点(27100)和从节点(27101)都会增加一个新的数据库test和新的集合testCollection
默认情况下,MongoDB会阻止对从节点的查询
mongo --port 27101
rs.slaveOk(1) 设置从节点允许读取操作
10.2.2 主从故障切换
关闭主节点:
use admin
db.shutdownServer()
从节点(27101)上查看:
mongo --port 27101
rs.status()
27101 变成了主节点
db.testCollection.insert({"name":"mytest-New27101"})
在27101中插入新的数据
db.testCollection.insert({"name":"mytest-New27101"})
重新启动27100:
mongod --replSet mg-cluster0 --dbpath F:\mongodb\cluster0\node1 --port 27100
在27100 查询
rs.status()
27100被当做从节点,并且在其被关闭的时候,27101新插入的数据,被同步到了27100节点上
db.testCollection.find()
10.3 复制集群工作原理
复制集依赖两个基本机制: oplog 和 hearbeat
oplog 允许复制数据
hearbeat监控状态并触发灾备
11 分片(Sharding)
mongodb的扩展方式---分片,如果业务数据和系统负载不断增加,可以通过分片来解决。
分片就是指将数据拆分,分散到不同的服务器上,从而处理更大的负载,存储大数据。
当数据增大到一定程度时,查询数据会变的很慢,难以忍受的地步,严重影响用户体验。往往就会根据业务对大表大数据库进行分表分库操作,人为的按照某种协定好的策略将若干不同的数据存储到不同的数据库服务器上,应用程序管理不同服务器上的不同数据,每台服务器上的连接都是完全独立的。在我曾经工作过的地方,mysql分表分库大量应用,比如将论坛附件表根据uid拆分成10个表00-09,取模10,也就是取uid最后两位;将post_000到post_014存在db1服务器上,将post_015到post_029存在db2服务器上,如此类推。这种分表分库可以很好的工作,弊端就是非常难以维护,调整数据分布和服务器负载,添加或减除节点非常困难,变一处而动全身。
mongodb支持自动分片,集群自动的切分数据,做负载均衡。避免上面的分片管理难度。
mongodb分片是将集合切合成小块,分散到若干片里面,每个片负责所有数据的一部分。这些块对应用程序来说是透明的,不需要知道哪些数据分布到哪些片上,甚至不在乎是否有做过分片,应用程序连接mongos进程,mongos知道数据和片的对应关系,将客户端请求转发到正确的片上,如果请求有了响应,mongos将结果收集起来返回给客户端程序。
分片适用场景:
1. 服务器磁盘不够用
2. 单个mongod不能满足日益频繁写请求
3. 将大量数据存放于内存中提高性能
11.1 什么是分片集群
11.2 什么时候分片
11.3 分片集群的组件
分片集群由 分片、 mongos路由器、configServer配置服务器组成
11.4 分片集群中的数据分散方式
11.4.1 数据库分片
11.4.2 集合分片
11.5 搭建分片集群
① 配置服务器。是一个独立的mongod进程,保存集群和分片的元数据,即各分片包含了哪些数据的信息。最先开始建立,启用日志功能。像启动普通的mongod一样启动配置服务器,指定configsvr选项。不需要太多的空间和资源,配置服务器的1KB空间相当于真是数据的200MB。保存的只是数据的分布表。当服务不可用,则变成只读,无法分块、迁移数据。
② 路由服务器。即mongos,起到一个路由的功能,供程序连接。本身不保存数据,在启动时从配置服务器加载集群信息,开启mongos进程需要知道配置服务器的地址,指定configdb选项。
③ 分片服务器。是一个独立普通的mongod进程,保存数据信息。可以是一个副本集也可以是单独的一台服务器。
11.5.1 启动 mongod 和 configserver
三台服务器:
172.21.4.104
172.21.4.31
172.21.4.103
在172.21.4.104 上安装:
实例 |
配置 |
说明 |
monogs |
172.21.4.104:40000 |
monogs |
configsvr |
172.21.4.104:28018 |
复制集-configsvr |
shard-a |
172.21.4.104:30000 |
复制集-a-Primay |
shard-b |
172.21.4.104:30103 |
复制集-b-Abr |
配置文件:
shard-a:
shard-b:
configsvr:
1.shard-a:
mongod --config "D:\mongodb\shard-a\bin\mongod.cfg" --install --serviceName "MongoDb-Cluster-Shard-a" --serviceDisplayName "MongoDb-Cluster-Shard-a"
2.shard-b:
mongod --config "D:\mongodb\shard-b\bin\mongod.cfg" --install --serviceName "MongoDb-Cluster-Shard-b" --serviceDisplayName "MongoDb-Cluster-Shard-b"
3.configsvr
mongod --config "D:\mongodb\configsvr\bin\mongod.cfg" --install --serviceName "MongoDb-Cluster-Configsvr" --serviceDisplayName "MongoDb-Cluster-Configsvr"
在172.21.4.31 上安装:
实例 |
配置 |
说明 |
monogs |
172.21.4.31:40000 |
monogs |
configsvr |
172.21.4.31:28018 |
复制集-configsvr |
shard-a |
172.21.4.31:30002 |
复制集-a-Abr |
shard-b |
172.21.4.31:30101 |
复制集-b-Primary |
在172.21.4.103 上安装:
实例 |
配置 |
说明 |
monogs |
172.21.4.103:40000 |
monogs |
configsvr |
172.21.4.103:28018 |
复制集-configsvr |
shard-a |
172.21.4.103:30001 |
复制集-a-Secondary |
shard-b |
172.21.4.103:30102 |
复制集-b- Secondary |
11.5.2 配置复制集:
配置复制集a:
mongo --host 172.21.4.104 --port 30000
rs.initiate()
rs.add("172.21.4.103:30001")
rs.addArb("172.21.4.31:30002")
rs.status()
1. STARTUP:刚加入到复制集中,配置还未加载
2. STARTUP2:配置已加载完,初始化状态
3. RECOVERING:正在恢复,不适用读
4. ARBITER: 仲裁者
5. DOWN:节点不可到达
6. UNKNOWN:未获取其他节点状态而不知是什么状态,一般发生在只有两个成员的架构,脑裂
7. REMOVED:移除复制集
8. ROLLBACK:数据回滚,在回滚结束时,转移到RECOVERING或SECONDARY状态
9. FATAL:出错。查看日志grep “replSet FATAL”找出错原因,重新做同步
10. PRIMARY:主节点
11. SECONDARY:备份节点
配置集群Shard-b:
mongo --host 172.21.4.31 --port 30101
rs.initiate()
rs.add("172.21.4.103:30102")
rs.addArb("172.21.4.104:30103")
rs.status()
或者
rs.initiate({
"_id": "cluster-shard-b",
"members": [
{
"_id": 1,
"host": "172.21.4.31:30101",
"priority": 1
},
{
"_id": 2,
"host": "172.21.4.103:30102",
"priority": 1
},
{
"_id": 2,
"host": "172.21.4.104:30103",
"priority": 0,
"arbiteOnly'": true
}
]
})
配置configServer复制集:
mongo "172.21.4.103:28018"
rs.initiate()
rs.add("172.21.4.104:28018")
rs.add("172.21.4.31:28018")
11.5.3 启动 mongos
配置文件:
systemLog:
destination: file
logAppend: true
path: D:\mongodb\mongos\log\mongos.log
net:
port: 40000
bindIp: 172.21.4.103
sharding:
configDB: cluster-shard-confisvr/172.21.4.103:28018,172.21.4.104:28018,172.21.4.31:28018
启动为windows 服务:
mongos --config "D:\mongodb\mongos\bin\mongod.cfg" --install --serviceName "MongoDb-Cluster-Mongos" --serviceDisplayName "MongoDb-Cluster-Mongos"
日志:
11.5.4 配置分片集群
连接mongos:
mongo --host 172.21.4.103 --port 40000
添加分片shard-a:
sh.addShard("cluster-shard-a/172.21.4.104:30000,172.21.4.103:30001")
添加分片shard-b:
sh.addShard("cluster-shard-b/172.21.4.31:30101,172.21.4.103:30102")
mongos 的config 数据库
查看分片状态:
sh.status()
11.5.5 对数据库和集合进行分片
演示示例1 (暂时没完成, 直接看演示示例2)
给数据库cloud-docs 启动分片:
sh.enableSharding("cloud-docs")
use config
db.databases.find().pretty()
集合分片:
sh.shardCollection("cloud-docs.spreadsheets", {username: 1, _id:1})
use config
db.collections.find().pretty()
创建数据库和集合:
连接 mongo --host 172.21.4.103 --port 30000
use cloud-docs
db.spreadsheets.insert({
"filename":"sheet-1",
"updated_at":new Date(),
"username":"banks",
data: "RAw Data"
});
插入数据成功后,
在每个分片上,cloud-docs.spreadsheets 集合自动创建 与 片键对应的索引。
mongo --host 172.21.4.103 --port 30000
use cloud-docs
db.spreadsheets.getIndexes()
分片的状态;
mongos>sh.status()
批量插入数据:
检查分片
use config
db.chunks.count()
演示示例2:
连接mongs,
user shard-test
批量插入数据:
for(i=0; i<100000; i++){
db.collection1.insert({"username": "user"+i, "createtime":new Date()})
}
让数据库shard-test 支持分片
sh.enableShard("shard-test")
sh.shardCollection("shard-test.collection1",{"username":1, "_id":1})
提示得在集合中创建跟片键对应的索引
db.collection1.createIndex({"username":1, "_id":1})
再执行:
sh.shardCollection("shard-test.collection1",{"username":1, "_id":1})
使用指定的片键 {"username":1, "_id":1} ,对 集合进行分片
查看集合分片状态:
db.collection1.stats().sharded
查看集群的分片状态:
sh.status()
db.printShardingStatus()
查看chunk分布:
use config
db.chunks.count()
db.chunks.find().pretty()
db.chunks.find({"ns":"shard-test.collection1"}).pretty()
db.chunks.find({"ns":"shard-test.collection1"}).pretty()
注意到:
此时,我只插入了少量的数据,这些数据没有超过 chunk 的最小的容量64MB,
所以数据都存储在 1 个 chunk 中。
//db.collection1.stats().size
批量插入大量数据,使得数据量大于最小chunk 的值(64MB),这样就会产生多个chunk 的分割。
修改chunk 的大小
https://docs.mongodb.com/manual/tutorial/modify-chunk-size-in-sharded-cluster/
这次使用C#Drive 批量插入数据:
db.printShardingStatus()
或者这样查询查询
use config
db.chunks.find({"ns":"shard-test.collection1"}).pretty()
db.chunks.find({"ns":"shard-test.collection1"}).count()
查询分割和迁移情况:
use config
db.changelog.find({"ns":"shard-test.collection1", "what":"multi-split"}).count()
发生了 20 次 分割,
db.changelog.find({"ns":"shard-test.collection1", "what":"moveChunk.commit"}).count()
发生了9次数据迁移
查看具体的某次迁移信息:
db.changelog.findOne({"ns":"shard-test.collection1", "what":"moveChunk.commit"})
11.6 分片集群的查询和索引
12 其它
导入数据
mongoimport --db 数据库名 --collection 集合名 --type csv --headerline --ignoreBlanks --file CSV文件存放路径