关于mongodb的学习与探索二

前言

在上一篇文章中咱们了解到了mongodb的基本操做,这一章咱们更进一步继续来探讨mongodb,废话很少说,直接入正题吧。前端

mongodb的高级用法

聚合

mongodb中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果。有点相似sql语句中的count(*).java

例如如今有个需求,有一个保存这文章的集合,你可能但愿找出发表文章最多的那个做者,假设每篇文章被保存为mongodb中的一个文档,这个需求咱们怎么去实现呢?下面咱们就一步一步的来实现这个需求。node

aggregate()的用法

db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)python

假设集合中的数据以下:mysql

{ "_id" : ObjectId("5a338a31ae83f6d96d3ef220"), "title" : "mongodb", "author" : "ck" }
{ "_id" : ObjectId("5a338a38ae83f6d96d3ef221"), "title" : "java", "author" : "ck" }
{ "_id" : ObjectId("5a338a4dae83f6d96d3ef222"), "title" : "node", "author" : "st" }
复制代码

首先咱们先计算出每一个做者缩写的文章数并排序,使用aggregate()计算结果以下所示:git

> db.col.aggregate([{ $group: { _id: "$author", num: { $sum : 1 } } },{ $sort : { "_id":1 } }])
{ "_id" : "ck", "num" : 2 }
{ "_id" : "st", "num" : 1 }
复制代码

直接一步到位的以下所示:github

> db.col.aggregate([{ $group: { _id: "$author", num: { $sum : 1 } } },{ $sort : { "_id":1 } }, { $limit:1 }])
{ "_id" : "ck", "num" : 2 }
复制代码

下表展现了一些聚合的表达式:算法

表达式 描述 实例
$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的聚合管道将MongoDB文档在一个管道处理完毕后将结果传递给下一个管道处理。管道操做是能够重复的。 表达式:处理输入文档并输出。表达式是无状态的,只能用于计算当前聚合管道的文档,不能处理其它的文档。 这里咱们介绍一下聚合框架中经常使用的几个操做:sql

$project:修改输入文档的结构。能够用来重命名、增长或删除域,也能够用于建立计算结果以及嵌套文档。mongodb

match:用于过滤数据,只输出符合条件的文档。match使用MongoDB的标准查询操做。

$limit:用来限制MongoDB聚合管道返回的文档数。

$skip:在聚合管道中跳过指定数量的文档,并返回余下的文档。

$unwind:将文档中的某一个数组类型字段拆分红多条,每条包含数组中的一个值。

$group:将集合中的文档分组,可用于统计结果。

$sort:将输入文档排序后输出。

$geoNear:输出接近某一地理位置的有序文档。

管道操做符实例

一、$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管道操做符处理后,前五个文档被"过滤"掉。

复制(副本集)

复制集简介

目前咱们一直使用的是单台服务器,一个mongod服务器进程。若是只是用做学习和开发,这是能够的,可是若是用到生产环境中,风险会很高。若是服务器崩溃了或者不可访问了怎么办?数据库至少会有一段时间不可用。若是是硬件除了问题,可能须要将数据转移到另外一个机器上。在最坏的状况下,磁盘或者网络问题可能会致使数据损坏或者数据不可访问。

使用复制能够将数据副本保存到多台服务器上,建议在全部的生产环境中都要使用。使用mongodb的复制功能,即便一台或多台服务器出错,也能够保证应用程序正常运行和数据安全。

复制集功能

保障数据的安全性

数据高可用性

灾难恢复

无需停机维护(如备份, 重建索引, 压缩)

分布式读取数据

复制集特性

1.数据的一致性:主节点是惟一的,没有mysql那样的双主结构,若是当前主节点出现故障后,集群会自动容灾,经过选举,来选举出来一个合适的从节点来充当新的主节点,因此主节点是惟一的,但不是固定的。

2.大多数原则:集群存货节点小于等于二分之一时集群则不可写,只可读。若是复制集的服务器挂了通常就无法选举了,将所有将为从节点。

3.从库没法写入:只有主节点可写入数据,从节点只可读。

关于复制集以及下面的分片这一块,想深刻研究的同窗能够自行学习,原谅我只是个前端,哈哈。。

分片

分片简介

分片是指将数据拆分,将其分散存放在不一样的机器上的过程。有时也用分区来表示这个概念。将数据分散到不一样的机器上,不须要功能强大的大型计算机就能够存储更多的数据,处理更大的负载。

几乎全部数据库软件都能进行手动分片。应用须要维护与若干不一样数据服务器的连接,每一个连接仍是彻底独立的。应用程序管理不一样服务器上不一样数据的存储,还管理在合适的数据上查询数据的工做。这种方法能够很好的工做,可是很是难以维护,好比向集群添加节点或从集群删除节点都很款南,调整数据分布和负载模式也不轻松。

mongodb支持自动分片,可使数据库架构对应用程序不可见,也能够简化系统管理。对应用程序而言,好像始终在使用一个单机的mongodb服务器同样。另外一方面,mongodb自动处理数据在分片上的分部,也更容易添加和删除分片。

无论从开发角度仍是运营角度来讲,分片都是最困难最复杂的mongodb配置方式。

理解集群的组件

mongodb的分片机制容许你建立一个包含许多台机器(分片)的集群,将数据子集分散在集群中,每一个分片维护者一个数据集合的子集。与单机服务器和副本集相比,使用集群架构可使应用程序具备更大的数据处理能力。

这里有一点要注意,许多人可能会混淆复制和分片的概念。记住,复制是让多台服务器都拥有一样的数据副本,每一台服务器都是其余服务器的镜像,而每个分片都有其余分片拥有不一样的数据子集。

分片的目标之一是建立一个拥有5台、10台甚至1000台机器的集群,整个集群对应用程序来讲就像是一台单机服务器。为了对应用程序隐藏数据库架构的细节,在分片以前要先执行mongos进行一次路由过程。这个路由服务器维护着一个“内容列表”,指明了每一个分片包含什么数据内容。应用程序只须要链接到路由服务器,就能够像使用单机服务器同样进行正常的请求了,以下图所示。路由服务器知道哪些数据位于哪一个分片,能够将请求转发给相应的分片。每一个分片对请求的相应都会发送给路由服务器,路由服务器将全部相应合并在一块儿,返回给应用程序。对应用程序来讲,它只知道本身是链接到了一台单机mongod服务器,以下图所示:

1-1

1-2

mongodb的安全加固

众所周知,数据安全很是重要,那么咱们应该怎么对咱们的mongodb进行安全加固呢?

修改默认端口

修改默认的mongodb端口(默认为:27017)为其余端口。

不要把mongodb服务器直接部署在外网上

1.经过安全组防火墙或服务器操做系统配置的防火墙对访问源IP进行控制,若是仅对内网服务器提供服务,建议禁止将mongodb服务发布到互联网上。

使用—bind_ip选项。

该选项能够限制监听接口IP,当在启动mongodb的时候,使用 --bind_ip 192.168.0.1 表示启动IP地址绑定,数据库实例将只监听192.168.0.1的请求。

启动基于角色的登陆认证功能。

在admin数据库中建立用户,如用户名supper,密码supWDxsf67%H(此处为举例说明,请勿使用此帐号密码)。

1.在未开启认证的环境下,登陆到数据库。

> [mongodb@rac3 bin]$ ./mongo 127.0.0.1:27028 (此处修改了默认端口)
MongoDB shell version: 2.0.1
connecting to: 127.0.0.1:27028/test
复制代码

2.切换到admin数据库

> use admin
switched to db admin
复制代码

3.建立管理员帐号

> db.addUser("supper", "supWDxsf67%H")或
> db.createUser({user:"supper",pwd:"supWDxsf67%H",roles:["root"]})
{ "n" : 0, "connectionId" : 4, "err" : null, "ok" : 1 }
{
"user" : "supper",
"readOnly" : false,
"pwd" : "51a481f72b8b8218df9fee50b3737c44",
"_id" : ObjectId("4f2bc0d357a309043c6947a4")
}
复制代码

管理员帐号将在system.users中。

> db.getCollectionNames()
[ "system.indexes", "system.users", "system.version" ]
复制代码

说明:

mongodb从v3版本开始取消使用addUser方法,采用db.createUser方法建立用户;

帐号不要设置为常见帐号,密码须要知足必定的复杂度,长度至少八位以上,并包括大小写字母、数字、特殊字符混合体,不要使用生日、姓名、身份证编号等常见密码。

4.验证用户是否建立成功。

> db.auth("supper","supWDxsf67%H")
> exit "system.version" ]
bye
复制代码

5.结束进程,重启MongoDB服务。

> ./mongod --dbpath=/path/mongodb --bind_ip=192.168.0.1 --port=27028 --fork=true logpath=/path/mongod.log &
复制代码

说明:

    • admin.system.users中将会保存比在其它数据库中设置的用户权限更大的用户信息,拥有超级权限,也就是说在admin中建立的用户能够对mongodb中的其余数据库数据进行操做。
    • MongoDB系统中,数据库是由超级用户来建立的,一个数据库能够包含多个用户,一个用户只能在一个数据库下,不一样数据库中的用户能够同名。
    • 特定数据库(好比DB1)的用户User1,不可以访问其余数据库DB2,可是能够访问本数据库下其余用户建立的数据。
    • 不一样数据库中同名的用户不可以登陆其余数据库,好比DB一、DB2都有user1,以user1登陆DB1后,不可以登陆到DB2进行数据库操做。
    • 在admin数据库建立的用户具备超级权限,能够对mongodb系统内的任何数据库的数据对象进行操做。
    • 使用db.auth()能够对数据库中的用户进行验证,若是验证成功则返回1,不然返回0。 db.auth()只能针对登陆用户所属的数据库的用户信息进行验证,不能验证其余数据库的用户信息。
禁用HTTP和REST端口。

MongoDB自身带有一个HTTP服务和并支持REST接口(在V2.6之后这些接口默认是关闭的)。MongoDB默认使用默认端口监听Web服务,通常不须要经过Web方式进行远程管理,建议禁用。 修改配置文件或在启动的时候选择–nohttpinterface参数便可。

nohttpinterface = false
复制代码
开启日志审计功能。

审计功能能够用来记录用户对数据库的全部相关操做。这些记录可让系统管理员在须要的时候分析数据库在什么时段发生了什么事情。

使用SSL加密功能。

MongoDB集群之间以及从客户端链接到MongoDB实例的链接应该使用SSL。使用SSL对性能没有影响而且能够防范相似于man-in-the-middle的攻击。

注意MongoDB社区版默认并不支持SSL。您能够选用MongoDB企业版(支持SSL),或者从源码从新编译MongoDB并使用—ssl选项来得到SSL功能。

以上全部配置,推荐以配置文件形式保存配置。

[mongodb@rac3 bin]$ vim /path/mongod.conf
port=27028-------端口。默认为27017端口,MongoDB的默认服务TCP端口,监听客户端链接。要是端口设置小于1024,好比1021,则须要root权限启动,不能用mongodb账号启动,(普通账号即便是27017也起不来)不然报错:[mongo --port=1021 链接]
bind_ip=192.168.0.1------绑定地址。默认127.0.0.1,只能经过本地链接。进程绑定和监听来自这个地址上的应用链接。要是须要给其余服务器链接,则须要注释掉这个或则把IP改为本机地址,如192.168.200.201[其余服务器用 mongo --host=192.168.200.201 链接] ,能够用一个逗号分隔的列表绑定多个IP地址。
logpath=/path/mongod.log------开启日志审计功能,此项为日志文件路径,能够自定义指定。
pidfilepath=/path/mongod.pid------进程ID,没有指定则启动时候就没有PID文件。
auth=true------用户认证,默认false。不须要认证。当设置为true时候,进入数据库须要auth验证,当数据库里没有用户,则不须要验证也能够操做。直到建立了第一个用户,以后操做都须要验证。
logappend=true------写日志的模式:设置为true为追加。默认是覆盖。若是未指定此设置,启动时MongoDB的将覆盖现有的日志文件。
fork=true------是否后台运行,设置为true 启动 进程在后台运行的守护进程模式。默认false。
nohttpinterface = false------是否禁止http接口,即28017 端口开启的服务。默认false,支持。
复制代码

而后,启动MongoDB服务时加载配置文件。

[mongodb@rac3 bin]$ ./mongod -f /path/mongod.conf
复制代码
对业务关键敏感数据进行加密存储。

建议您梳理业务数据,对关键的敏感数据加密后入库,例如:帐号、密码、邮箱地址、手机号码、身份ID等其余数据。加密算法推荐选择国际通用加密算法和屡次加盐组合自定义算法,防止加密算法被破解。

即便黑客获取数据后,也查看不了数据,经过“看不懂”的数据加密方式将损失降到最低。

对数据进行本地异地备份。

完善的备份策略是保证数据安全的最后一根救命稻草。

推荐:可靠的本地备份+远程备份存储方案

本地备份

1.MongoDB备份方式

>mongodump -h dbhost -d dbname -o dbdirectory
-h:
MongDB所在服务器地址,例如:127.0.0.1,固然也能够指定端口号:127.0.0.1:27017
-d:
须要备份的数据库实例,例如:test
-o:
备份的数据存放位置,例如:c:\data\dump,该目录须要提早创建,在备份完成后,系统自动在dump目录下创建一个test目录,这个目录里面存放该数据库实例的备份数据。
复制代码

2.MongoDB数据恢复

mongodb使用 mongorestore 命令来恢复备份的数据。
语法
mongorestore命令脚本语法以下:
>mongorestore -h dbhost -d dbname --directoryperdb dbdirectory
-h:
MongoDB所在服务器地址
-d:
须要恢复的数据库实例,例如:test,这个名称也能够和备份时候的不同,好比test2。
--directoryperdb:
备份数据所在位置,例如:c:\data\dump\test。
--drop:
恢复的时候,先删除当前数据,而后恢复备份的数据。就是说,恢复后,备份后添加修改的数据都会被删除,慎用!
复制代码

3.Mongodump命令可选参数列表以下所示。

语法 描述 实例
mongodump --host HOST_NAME --port PORT_NUMBER 该命令将备份全部mongodb数据 mongodump --host w3cschool.cc --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

4.备份策略

全量备份:能够最快的时间快速恢复全部数据,缺点是备份成本大,时间长

全量备份+增量备份:能够较快的恢复全部数据,缺点是恢复时间长,若是增量数据有问题,没法恢复全部数据。

搭建从库:直接切换到从库,前提是从库的数据安全可靠。

欢迎各路大佬对文章错误的地方进行指正,万分感谢,共同窗习进步。博主的GitHub地址,能够在GitHub提Issues或者直接在文章下面评论区留言。
相关文章
相关标签/搜索