1.MapReduce

作用

在用 MongoDB 查询时,若返回的数据量很大,或者做一些比较复杂的统计和聚合操作做花费的时间很长时,可以使用 MongoDB 中的 mapReduce 进行实现。
mapReduce 是个灵活且强大的数据聚合工具,它的好处是可以把一个聚合任务分解为多个小的任务,分配到多个服务器上并行处理。
MapReduce是一个编程模型,封装了并行计算、容错、数据分布、负载均衡等细节问题。
通俗理解,aggragation和mapreduce都可以实现聚合,但是mapreduce支持分片模式存储的分布式数据聚合,可以处理更大的数据量

命令格式

在 mapReduce 命令中要实现两个函数,分别是 map 函数和 reduce 函数,其中 map 函数调用 emit(key, value),遍历集合中的所有记录,并将 key 与 value 传递给 reduce 函数进行处理,

  1. db.collection_name.mapReduce(
  2. function() {emit(key, value);}, // map 函数
  3. function(key, values) {return reduceFunction}, // reduce 函数
  4. {
  5. out: collection,
  6. query: document,
  7. sort: document,
  8. limit: number
  9. }
  10. )

参数说明如下:

  1. map 函数:一个 javascript 函数,它用一个键映射一个值并发出一个键值对;

常用格式:emit(p1, p2)

  • p1:需要分组的字段,this.字段名。
  • p2:需要进行统计的字段,this.字段名。可以设置为常数1
  1. reduce 函数:一个 javascript 函数,用于减少或分组具有相同键的所有文档;

其中重点关注相同键这个词,map处理的键值对交给reduce处理时,是按照键值分组的
统计常用的方法:

  1. //对数值类型进行求和。(PS:Arrays.sum方法在js中时无效的,只在mongo shell js中有效)
  2. var reduce = function(key, values){ return Array.sum(values); }
  3. //对字符串类型进行拼凑
  4. var reduce = function(key, values){ return values.join(', '); }
  1. out:指定 map-reduce 查询结果的位置;
  2. query:指定用于选择文档的可选选择条件;
  3. sort:指定可选的排序条件;
  4. limit:指定要返回的最大文档数(可选)。

    验证

  5. 插入测试数据

假设统计当前班级成员,包括姓名,年龄,性别三个字段
参数如下

  1. [
  2. {
  3. "name":"ftc",
  4. "age":18,
  5. "sex":"boy"
  6. },
  7. {
  8. "name":"gn",
  9. "age":18,
  10. "sex":"girl"
  11. },
  12. {
  13. "name":"wqw",
  14. "age":20,
  15. "sex":"girl"
  16. },
  17. {
  18. "name":"skx",
  19. "age":17,
  20. "sex":"girl"
  21. },
  22. {
  23. "name":"wkf",
  24. "age":15,
  25. "sex":"girl"
  26. },
  27. {
  28. "name":"wys",
  29. "age":24,
  30. "sex":"girl"
  31. },
  32. {
  33. "name":"nn",
  34. "age":26,
  35. "sex":"girl"
  36. }
  37. ]
  1. 统计年龄大于17岁的学生,男女生分别的个数是多少

    1. var map = function() { emit(this.sex,1); }
    2. var reduce = function(key, values) { return Array.sum(values)}
    3. var options = { query:{age:{$gt:17}}, out:"result"}
    4. db.test.mapReduce(map,reduce,options)
    5. db.result.find()

    image.png

  2. 统计年龄大于17岁的学生,男女生分别的详细列表

    1. var map = function() { emit(this.sex,this.name); }
    2. var reduce = function(key, values){ return values.join(', '); }
    3. var options = { query:{age:{$gt:17}}, out:"result"}
    4. db.test.mapReduce(map,reduce,options)
    5. db.result.find()

    image.png

    2.正则表达式

    作用

    mongo中同样提供了正则表达式查询模式,可以在不建立文本索引的情况下,进行文本字段的匹配查询。MongoDB 使用 PCRE(Perl 兼容的正则表达式)作为正则表达式语言
    PCRE具体参考链接

    命令格式

    db.${collectionName}.find(${fieldName:{$regex:”具体参数”,$options:”具体可选项”}})

  3. $regex:使用正则表达式进行匹配查询

  4. $options:正则表达式可选项,比较常用的是”$i”,代表不区分大小写

    验证

  5. 存入测试数据(与mapReduce中参数一致)

  6. 查询名称中带有w的学生:db.test.find({name:{$regex:”w”}})

image.png

  1. 此时每个文档新增一个tags字段

    1. [
    2. {
    3. "name":"ftc",
    4. "age":18,
    5. "sex":"boy",
    6. "tags":[
    7. "帅哥",
    8. "器大",
    9. "活好"
    10. ]
    11. },
    12. {
    13. "name":"gn",
    14. "age":18,
    15. "sex":"girl",
    16. "tags":[
    17. "美女",
    18. "长腿"
    19. ]
    20. },
    21. {
    22. "name":"wqw",
    23. "age":20,
    24. "sex":"girl",
    25. "tags":[
    26. "熟女",
    27. "性感"
    28. ]
    29. },
    30. {
    31. "name":"skx",
    32. "age":17,
    33. "sex":"girl",
    34. "tags":[
    35. "美女",
    36. "嗓音独特"
    37. ]
    38. },
    39. {
    40. "name":"wkf",
    41. "age":15,
    42. "sex":"girl",
    43. "tags":[
    44. "美女",
    45. "气质出众"
    46. ]
    47. },
    48. {
    49. "name":"wys",
    50. "age":24,
    51. "sex":"girl",
    52. "tags":[
    53. "少女",
    54. "好看"
    55. ]
    56. },
    57. {
    58. "name":"nn",
    59. "age":26,
    60. "sex":"girl",
    61. "tags":[
    62. "美女",
    63. "性感"
    64. ]
    65. }
    66. ]
  2. 查询标签为美女的学生:db.test.find({tags:{$regex:”美女”}})

image.png

  1. 此时修改skx名称为SKX:db.test.update({name:”skx”},{$set:{name:”SKX”}})
  2. 查询名称中带有s的学生:db.test.find({name:{$regex:”s”,$options:”$i”}})

image.png

3.GridFS

作用

MongoDb GridFS 是MongoDB的文件存储方案,主要用于存储和恢复那些超过16M(BSON文件限制)的文件(如:图片、音频等),对大文件有着更好的性能。
在存储文件时 GridFS 可以将一个文件分为多个数据块,并将每个数据块存储在一个单独的文档中,每个文档最大为 255KB。
通俗来讲就是用来存储大型文件(大于16M的文件)的,可以在分布式项目中用来存储大型文件

原理

默认情况下,GridFS 使用 fs.files 和 fs.chunks 两个集合来存储文件的元数据和块。

  1. fs.files:每个大文件会生成一个文档,用来存储文档的明细信息,具体字段如下

image.png

  1. fs.chunks:每个大文件会生成一个或多个文档。每个区块都由其唯一的 ObjectId(_id)字段标识。fs.files 用作父文档,fs.chunks 文档中的 files_id 字段将块链接到fs.file的_id字段。具体字段如下

image.png

  1. 存储架构图

image.png

  1. 读取时,先查询fs.files集合中对应的唯一文档,然后查询fs.chunks集合中关联的数据块文档,通过n字段按顺序分段读取整个文档的内容

    使用

    存储文件 PUT

    示例命令:mongofiles -h 120.48.107.224 -u test -p test —db files -l C:\Users\86176\Desktop\1.jpg put 1.jpg
    如图,保存完成
    image.png
    查询对应信息,如图,因为fs.chunk.data数据过多不好展示,因此不展示
    image.png

    获取文件 GET

    shell命令行默认目录下,此时并没有1.jpg
    image.png
    示例命令:mongofiles -h 120.48.107.224 -u test -p test —db files get 1.jpg
    执行完下载后,获取到了1.jpg文件
    image.png

    列出所有文件 LIST

    示例命令:mongofiles -h 120.48.107.224 -u test -p test —db files list
    如图,显示出文件夹以及每个文件的大小
    image.png

    删除文件 DELETE

    示例命令:mongofiles -h 120.48.107.224 -u test -p test —db files delete 1.jpg
    如图删除成功
    image.png
    此时在进行查找,同名文件已全部删除
    image.png

    注意

  2. 如果系统中大文件数量处于不断增加状态,还是建议使用专用的文件存储设备

  3. GridFS不支持多文档事务,操作不是原子性的,这个要注意

    4.数据备份

    mongo中通过mongodump工具进行数据的备份,mongodump工具的下以及部署请参考链接

    命令格式

    mongodump -h dbhost -u username -p password -d dbname -c collectionName -o dbdirectory

  4. -h:非必传,缺省代表链接本机

  5. -u:非必传,用户名
  6. -p:非必传,密码
  7. -d:必传,备份数据库
  8. -c:非必传,指定备份集合。缺省代表备份整个数据库
  9. -o:必传,备份文件存储位置,对应目录需提前创建!!!!

命令示例:mongodump -h 120.48.107.224 -u test -p test -d files-c fs.chunks -o D:\Code\Base\MongoDB\dump

验证

  1. 上传一张图片到files数据库:mongofiles -h 120.48.107.224 -u test -p test —db files -l C:\Users\86176\Desktop\1.jpg put 1.jpg

image.png

  1. 对files数据库进行备份:mongodump -h 120.48.107.224 -u test -p test -d files -o D:\Code\Base\MongoDB\dump

image.png
备份文件格式如图
image.png

5.数据恢复

在进行了数据备份后,同样需要对数据进行恢复操作,mongo提供了mongorestore命令进行数据的恢复

命令格式

mongorestore -h dbhost -u username -p password -d dbname -c collectionName —dir dbdirectory

  1. -h:非必传,缺省代表链接本机
  2. -u:非必传,用户名
  3. -p:非必传,密码
  4. -d:必传,备份数据库
  5. -c:非必传,指定备份集合。缺省代表恢复整个数据库
  6. —dir:备份数据文件夹位置,需要具体到备份的数据库路径下!!!!

命令示例:mongorestore -h 120.48.107.224 -u test -p test -d files —dir D:\Code\Base\MongoDB\dump\files

验证

  1. 删除1.jpg文件:mongofiles -h 120.48.107.224 -u test -p test —db files delete 1.jpg

image.png

  1. 执行命令:mongorestore -h 120.48.107.224 -u test -p test -d files —dir D:\Code\Base\MongoDB\dump\files

如图,数据恢复成功
image.png

  1. 数据查看数据是否已恢复

如图,图片文件已重新恢复
image.png

6.统计与监控

在部署完Mongo服务器之后,为了保障 MongoDB 的正常运行。MongoDB 中提供了 mongostat 和 mongotop 两个命令来监控 MongoDB 的运行情况

mongostat

mongostat够检查所有正在运行的 mongod 实例的状态,并返回数据库操作的计数器。这些计数器包括插入、查询、更新、删除和游标。当您的内存不足、写入量不足或者出现一些性能问题时,该命令还会显示发生错误的时间,并显示锁定百分比。

命令格式

mongostat -h 120.48.107.224 -u root -p 123456—authenticationDatabase admin

验证

image.png
参数介绍如下:

  1. insert/s : 官方解释是每秒插入数据库的对象数量,如果是slave,则数值前有*,则表示复制集操作
  2. query/s : 每秒的查询操作次数
  3. update/s : 每秒的更新操作次数
  4. delete/s : 每秒的删除操作次数
  5. getmore/s: 每秒查询cursor(游标)时的getmore操作数
  6. command: 每秒执行的命令数,在主从系统中会显示两个值(例如 3|0),分表代表 本地|复制 命令

注: 一秒内执行的命令数比如批量插入,只认为是一条命令(所以意义应该不大)

  1. dirty: 仅仅针对WiredTiger引擎,官网解释是脏数据字节的缓存百分比
  2. used:仅仅针对WiredTiger引擎,官网解释是正在使用中的缓存百分比
  3. flushes:
  4. For WiredTiger引擎:指checkpoint的触发次数在一个轮询间隔期间

注:一般都是0,间断性会是1, 通过计算两个1之间的间隔时间,可以大致了解多长时间flush一次。flush开销是很大的,如果频繁的flush,可能就要找找原因了

  1. vsize: 虚拟内存使用量,单位MB (这是 在mongostat 最后一次调用的总数据)
  2. res: 物理内存使用量,单位MB (这是 在mongostat 最后一次调用的总数据)

注:这个和你用top看到的一样, vsize一般不会有大的变动, res会慢慢的上升,如果res经常突然下降,去查查是否有别的程序狂吃内存。

  1. qr: 客户端等待从MongoDB实例读数据的队列长度
  2. qw:客户端等待从MongoDB实例写入数据的队列长度
  3. ar: 执行读操作的活跃客户端数量
  4. aw: 执行写操作的活客户端数量

注:如果这两个数值很大,那么就是DB被堵住了,DB的处理速度不及请求速度。看看是否有开销很大的慢查询。如果查询一切正常,确实是负载很大,就需要加机器了

  1. netIn:MongoDB实例的网络进流量
  2. netOut:MongoDB实例的网络出流量

注:此两项字段表名网络带宽压力,一般情况下,不会成为瓶颈

  1. conn: 打开连接的总数,是qr,qw,ar,aw的总和

    mongotop

    命令可以跟踪并报告 MongoDB 实例的读写活动。默认情况下,mongotop 能够提供每个集合的水平统计数据,并每秒钟返回一次,您也可以根据需要对其进行修改。

    命令格式

    mongotop -h 120.48.107.224 ${秒数,非必填。缺省状态下每秒刷新一次}

    验证

    image.png
    如图,显示出所有集合每秒的读写数量

    7.Mongo中的定长集合

    概念

    mongo中大部分的集合都是动态集合,随着文档数递增而动态扩容
    而定长集合与动态集合不同,它的大小固定,当集合中文档的大小达到固定容量后,会淘汰掉最老的文档进而存储最新的文档,可以把定长集合理解为一个队列。示例如下图:
    image.png

    特点

  2. 支持insert操作,集合定长,当文档数达到固定大小后,会淘汰掉最老的文档

  3. 支持update操作,但是如果更新后整体文档大小超过固定大小,那么更新会失败
  4. 不支持remove操作
  5. 不会创建任何默认索引,_id字段也不会存在默认索引
  6. 文档的写入形式为顺序写,因此效率极高
  7. 文档的读取形式默认为顺序读,因此读取效率极高

    命令格式

  8. 创建一个定长集合:db.createCollection(“cappedCollcetion”,{capped:true,size:10000,max:1000})

  • capped:集合是否为定长集合
  • size:定长集合的容量,单位字节数
  • max:定长集合中最大文档数量
  1. 查看集合是否为定长集合:db.collectionName.isCapped()
  2. 将集合调整为定长集合:db.runCommand({“convertToCapped”:”cappedCollcetion”,size:10000})

    场景

  3. 热门数据缓存,当缓存热门数据达到固定大小后,会淘汰掉冷门数据,类似于LRU

  4. 定期时间段日志存储,过期日志淘汰
  5. 总结来说将定长集合当成一个队列即可,适用于队列场景的都适用于定长集合