十六、聚合
聚合用于处理数据(如统计平均值,求和等),并返回计算后的数据,类似于SQL中的count(*)。
语法:db.collection.aggregate(aggrefate_operation)
参数说明:
aggregate_operation --操作符,常见如下:
$project:修改输入文档的结构。可以用于重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。
$match:用于过滤数据,值输出符合条件的文档,用于标准查询操作。
$limit:用来限制聚合管道返回的文档数。
$sjip:在管道中跳过指定数量的文档,并当余下文档。
$unwind:将文档中的某一个数组类型拆分为多条,每条包含数组一个值。
$group:将集合的文档分组,可用于统计结果。相当于SQL中的group by。
$sort:将输出文档排序。
$geoNear:输出接近某一地理位置的有序文档。
实例:
集合数据:
{
_id: ObjectId(7df78ad8902c)
title: 'MongoDB Overview',
description: 'MongoDB is no sql database',
by_user: 'runoob.com',
url: 'http://www.runoob.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 100
},
{
_id: ObjectId(7df78ad8902d)
title: 'NoSQL Overview',
description: 'No sql database is very fast',
by_user: 'runoob.com',
url: 'http://www.runoob.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 10
},
{
_id: ObjectId(7df78ad8902e)
title: 'Neo4j Overview',
description: 'Neo4j is no sql database',
by_user: 'Neo4j',
url: 'http://www.neo4j.com',
tags: ['neo4j', 'database', 'NoSQL'],
likes: 750
},
计算出每个作者缩写的文章数:
> db.mycol.aggregate({$group: {_id: "$by_user", num_tutorial: {$sum: 1}}})
{
"result" : [
{
"_id" : "runoob.com",
"num_tutorial" : 2
},
{
"_id" : "Neo4j",
"num_tutorial" : 1
}
],
"ok" : 1
}
类似于SQL语句:
select by_user, count(*) from mycol group by by_user
聚合表达式:
表达式 | 描述 | 实例 |
---|---|---|
$sum | 计算总和。 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : "$likes"}}}]) |
$avg | 计算平均值 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$avg : "$likes"}}}]) |
$min | 获取集合中所有文档对应值得最小值。 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$min : "$likes"}}}]) |
$max | 获取集合中所有文档对应值得最大值。 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$max : "$likes"}}}]) |
$push | 将值加入一个数组中,不会判断是否有重复的值。 | db.mycol.aggregate([{$group : {_id : "$by_user", url : {$push: "$url"}}}]) |
$addToSet | 将值加入一个数组中,会判断是否有重复的值,若相同的值在数组中已经存在了,则不加入。 | db.mycol.aggregate([{$group : {_id : "$by_user", url : {$addToSet : "$url"}}}]) |
$first | 根据资源文档的排序获取第一个文档数据。 | db.mycol.aggregate([{$group : {_id : "$by_user", first_url : {$first : "$url"}}}]) |
$last | 根据资源文档的排序获取最后一个文档数据 | db.mycol.aggregate([{$group : {_id : "$by_user", last_url : {$last : "$url"}}}]) |
管道的概念
管道在Unix和Linux中一般用于将当前命令的输出结果作为下一命令的参数。
MongoDB中的聚合管道将文档在一个管道处理完毕后将结果传递给下一个管道处理。管道操作时可重复的。
表达式:处理输入文档并输出。表达式无状态,只能用于计算当前管道中的文档,不能处理其他文档。
实例1 $project:
db.article.aggregate(
{ $project : {
title : 1 ,
author : 1 ,
}}
);
结果中就只还有_id,tilte和author三个字段了,默认情况下_id字段是被包含的,如果要想不包含_id话可以这样:
db.article.aggregate(
{ $project : {
_id : 0 ,
title : 1 ,
author : 1
}});
实例2: $match:
db.articles.aggregate( [
{ $match : { score : { $gt : 70, $lte : 90 } } },
{ $group: { _id: null, count: { $sum: 1 } } }
] );
$match用于获取分数大于70小于或等于90记录,然后将符合条件的记录送到下一阶段$group管道操作符进行处理。
实例3 $skip:
db.article.aggregate(
{ $skip : 5 });
经过$skip管道操作符处理后,前五个文档被"过滤"掉。
十七、复制(副本集)
MongoDB的复制是将数据同步在多个服务器的过程。
复制提供数据的冗余备份,并在多个服务器上存储数据副本,提高了数据的可用性,并可保证数据的安全性。复制还允许从硬件故障和服务中断中恢复。
1、复制的优点:
- 保障数据的安全性
- 数据高可用性 (24*7)
- 灾难恢复
- 无需停机维护(如备份,重建索引,压缩)
- 分布式读取数据
2、mongodb复制的原理:
复制至少需要两个节点,一个主节点,负责处理客户端请求,其余从节点,负责复制主节点上的数据。常见的搭配方式为:一主一从、一主多从。
主节点记录其上面所有的操作oplog,从节点定期轮询主节点获取这些操作,然后对自己的数据副本执行相同的操作,从而保证和主节点数据保持一致。
如图所示:
上图所示,客户端从主节点读取数据,在客户端写入数据到主节点时,主节点与从节点进行数据交互保障数据一致性。
3、副本集的特征:
- N 个节点的集群
- 任何节点可作为主节点
- 所有写入操作都在主节点上
- 自动故障转移
- 自动恢复
4、mongodb中副本集的设置:
(1)关闭正在运行的mongodb服务器
(2)通过指定 --replSet 选项来启动mongoDB。--replSet 基本语法格式如下:
mongod --port "PORT" --dbpath "YOUR_DB_DATA_PATH" --replSet "REPLCA_SET_INSTANCE_NAME"
参数说明:
PORT --服务器端口
YOUR_DB_DATA_PATH --服务器地址URL
REPLCA_SET_INSTANCE_NAME --实例名
实例:
mongod --port 27017 --dbpath "D:\set up\mongodb\data" --replSet rs0
以上实例会启动一个名为rs0的mongodb实例,端口号为27017。
启动后会打开命令提示框并连接服务。
(3)在Mongo客户端使用命令 rs.initiate() 启动一个新的副本集。
(4)使用rs.conf() 来查看副本集配置。
(5)使用rs.status() 来查看副本集状态。
5、副本集添加成员
添加副本集成员需要使用多台服务器来启动mongo服务。进入mongo客户端,并使用rs.add()方法来添加副本集成员。
语法:
rs.add(HOST_NAME:PORT)
实例:
假设你已经启动了一个名为mongod1.net,端口号为27017的Mongo服务。 在客户端命令窗口使用rs.add() 命令将其添加到副本集中,命令如下所示:
rs.add("mongo1.net:27017")
MongoDB中你只能通过主节点将Mongo服务添加到副本集中, 判断当前运行的Mongo服务是否为主节点可以使用命令db.isMaster() 。
MongoDB的副本集与我们常见的主从有所不同,主从在主机宕机后所有服务将停止,而副本集在主机宕机后,副本会接管主节点成为主节点,不会出现宕机的情况。
十八、分片
分片技术可以满足mongodb中数据量大量增长的需求。当存储海量数据时,一台机器不足以存储数据,可能也不足以提供可接受的读写吞吐量,这时就需要通过多台机器上分割数据,是的数据库系统能存储和处理更多数据。
为啥要使用分片:
- 复制所有的写入操作到主节点
- 延迟的敏感数据会在主节点查询
- 单个副本集限制在12个节点
- 当请求量巨大时会出现内存不足。
- 本地磁盘不足
- 垂直扩展价格昂贵
分片结构:
三个主要组件:
Shard:用于存储实际的数据块,实际生产环境中一个shard server角色可以由几台机器组成一个replica set承担,防止主机单点故障。
Config Server:mongo实例,存储了整个ClusterMetadata,其中包括chunk信息。
Query Routers:前端路由,客户端由此接入,且让整个集群看起来像单一数据库,前端应用可以透明使用。
分片实例:
分片端口分布如下:
Shard Server 1:27020
Shard Server 2:27021
Shard Server 3:27022
Shard Server 4:27023
Config Server :27100
Route Process:40000
步骤一:启动Shard Server
[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
[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
注意:这里我们完全可以像启动普通mongodb服务一样启动,不需要添加—shardsvr和configsvr参数。因为这两个参数的作用就是改变启动端口的,所以我们自行指定了端口就可以。
步骤三:启动Router Server
/usr/local/mongoDB/bin/mongos --port 40000 --configdb localhost:27100 --fork --logpath=/www/mongoDB/shard/log/route.log --chunkSize 500
mongos启动参数中,chunkSize这一项是用来指定chunk的大小的,单位是MB,默认大小为200MB。
步骤四:配置Sharding
我们使用MongoDB Shell登录到mongos,添加Shard节点
[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端口(router server)即可。
十九、备份与恢复
1、数据备份
使用mongodump命令进行数据备份,该命令可以导出所有数据到指定目录中,也可以通过参数指定导出的数据量级转存的服务器。
语法:
mongodump -h dbhost -d dbname -o dbdirectory
参数说明:
-h --mongoDB所在的服务器地址,也可指定端口号,如:127.0.0.1:27017
-d --需要备份的数据库实例,例如:test
-o --备份的数据存放的位置,例如:c:\data\dump,该目录要提前创建,备份完成后,系统会自动在该目录下建立一个test目录,这个目录下存放数据库实例的备份数据。
实例:
本地使用27017端口启动mongodb服务。打开命令提示窗口,进入MongoDB安装目录下的bin目录执行mongodump命令:
> mongodump
执行完后,客户端自动连接到ip为127.0.0.1:27017的mongodb服务器上,并备份所有数据到bin/dump/目录中。输出结果:
命令可选参数列表:
语法 | 描述 | 实例 |
mongodump -host HOST_NAME --port PORT_NUMBER | 该命令备份所有的mongodb数据 | mongodump --host runoob,com --port 27017 |
mongodump --dbpath DB_PATH --out BACKUP_DIRECTORY | mongodump --dbpath /data/db/ --out /data/backup/ | |
mongodump --collection COLLECTION --db DB_NAME | 该命令将备份指定数据库的集合 | mongodump --collection mycol --db test |
2、数据恢复
mongorestore 命令用来恢复备份的数据。
语法:
mongorestore -h <hostname><:port> -d dbname <path>
参数说明:
--host <:port>, -h <:port> mongodb所在的数据库地址,默认为:localhost:27017
--db, -d 需要恢复的数据实例,例如:test。这个名字也可以和备份的时候不一样,如:test2
--drop 恢复的时候,先删除当前数据,然后恢复备份数据。即:恢复后备份后添加修改的数据都会被删除,谨慎使用
<path> 设置备份数据所在的位置,如:c:\data\dump\test。不能同时指定<path>和 --dir,--dir也可以设置备份的目录
--dir 设置备份的目录
实例:
执行mongorestore命令:
> mongorestore
执行完以上命令后输出:
二十、监控
MongoDB中提供了mongostat和mongotop 两个命令来监控mongodb的运行情况。
1、mongostat
mongostat是mongodb自带的状态检测工具,在命令行下使用。它会间隔固定时间获取mongodb的当前运行状态,并输出。如果你发现数据库突然变慢或者有其他问题的话,你第一手的操作就考虑采用mongostat来查看mongo的状态。
启动你的Mongod服务,进入到你安装的MongoDB目录下的bin目录, 然后输入mongostat命令,如下所示:
D:\set up\mongodb\bin>mongostat
输出结果:
2、mongotop
mongotop也是mongodb下的一个内置工具,mongotop提供了一个方法,用来跟踪一个MongoDB的实例,查看哪些大量的时间花费在读取和写入数据。 mongotop提供每个集合的水平的统计数据。默认情况下,mongotop返回数据的每一秒。
启动你的Mongod服务,进入到你安装的MongoDB目录下的bin目录, 然后输入mongotop命令,如下所示:
D:\set up\mongodb\bin>mongotop
输出结果:
带参数的命令:
(1)mongotop <sleeptime>
<sleeptime> 等待时间,为可选参数,不指定默认为1s。
(2)mongotop --locks
--locks 锁,用于报告每个数据库中锁的使用
输出结果字段说明:
ns --包含数据库的命名空间,后者结合了数据库名称和集合。
db --包含数据库名称,名为 . 的数据库针对全局锁定,而非特定数据库。
total --mongod 工作在这个命名空间的花费的时间总额。
read --mongod在此命名空间上花费在执行读操作时间。
write --mongod在此命名空间上花费在执行写操作时间。