MongoDB进阶系统学习3——MongoDB高级操作

第三部分:MongoDB高级操作

5 聚合分组统计(管道)

5.1 聚合aggregate

  • 聚合(aggregate)是基于数据处理的聚合管道,每个文档通过一个由多个阶段(stage)组成的管道,

  • 可以对每个阶段的管道进行分组、过滤等功能,然后经过一系列的处理,输出相应的结果。

  • db.集合名称.aggregate({管道:{表达式}})

  • 先传入数据到stu(学生)集合中
    db.stu.insert({name:“郭靖”, hometown:“蒙古”, age:20, gender:true})
    db.stu.insert({name:“黄蓉”, hometown:“桃花岛”, age:18, gender:false})
    db.stu.insert({name:“华筝”, hometown:“蒙古”, age:18, gender:false})
    db.stu.insert({name:“黄药师”, hometown:“桃花岛”, age:40, gender:true})
    db.stu.insert({name:“段誉”, hometown:“大理”, age:16, gender:true})
    db.stu.insert({name:“段王爷”, hometown:“大理”, age:45, gender:true})
    db.stu.insert({name:“洪七公”, hometown:“华山”, age:18, gender:true})

注意:
MongoDB语句可以现在pycharm中编写,然后复制到CMD窗口中
现在pycharm中使用ctrl+c复制命令,然后CMD窗口点击鼠标右键,就自动粘贴了
可以一次复制多行,有时候会出现粘贴不上去的情况

  • db.集合名称.aggregate({管道:{表达式}})

  • 管道和表达式都可以有多个

  • 管道:
    在mongodb中,⽂档处理完毕后, 通过管道进⾏下⼀次处理
    常用管道如下:
    $group: 将集合中的⽂档分组, 可⽤于统计结果
    $match: 过滤数据, 只输出符合条件的⽂档
    $project: 修改输⼊⽂档的结构, 如重命名、 增加、 删除字段、 创建计算结果
    $sort: 将输⼊⽂档排序后输出
    $limit: 限制聚合管道返回的⽂档数
    $skip: 跳过指定数量的⽂档, 并返回余下的⽂档
    $unwind: 将数组类型的字段进⾏拆分

  • 表达式:
    处理输⼊⽂档并输出
    语法:表达式:’$列名’
    常⽤表达式:
    $sum: 计算总和,
    $sum:1 表示以⼀倍计数
    $avg: 计算平均值
    $min: 获取最⼩值
    $max: 获取最⼤值
    $push: 在结果⽂档中插⼊值到⼀个数组中
    $first: 根据资源⽂档的排序获取第⼀个⽂档数据
    $last: 根据资源⽂档的排序获取最后⼀个⽂档数据

5.2 $group分组统计

  • $group注意点
    • $group对应字典中有几个键,结果中对应就有几个值
    • 分组依据必须放在_id的值中
    • 取不同的字段的时候需要使用 , 比 如 ,比如 ,country,$age
    • 取字典嵌套的字典中的值的时候 , , ,_id.country
    • 能够同时按照多个组进行分组
    • 管道依次按顺序处理,常用处理顺序过滤-分组-重整

实例

  • 语法格式:
    先写分组,必须使用_id作为键,然后里面的_id代表以哪个字段进行分组
    后面的字段是分组里面进行统计,求和,求平均值,最大值等等
    分组里面的键都是自己指定的,值是集合里面有的字段,前面都需要$符号

  • 统计整个文档

    • _id为null
    • 整个文档求和求平均值
      db.stu.aggregate(
      {KaTeX parse error: Expected '}', got 'EOF' at end of input: …d:null, count:{sum:1}, mean_age:{ a v g : " avg:" avg:"age"}}}
      )
  • 指定条件进行分组,然后统计

    • 按性别分组(注意KaTeX parse error: Expected 'EOF', got '}' at position 12: 符号不能遗漏,还要注意}̲不要遗漏) db.stu.ag…group:{_id:"$gender"}}
      )

    • 按性别分组,然后统计每个性别的和,同时求最小值
      db.stu.aggregate(
      {KaTeX parse error: Expected '}', got 'EOF' at end of input: group:{_id:"gender", count:{KaTeX parse error: Expected 'EOF', got '}' at position 6: sum:1}̲, min_age:{min:"$age"}}}
      )

    • 按家乡进行分组,统计个数,求平均年龄
      db.stu.aggregate(
      {KaTeX parse error: Expected '}', got 'EOF' at end of input: group:{_id:"hometown", count:{KaTeX parse error: Expected 'EOF', got '}' at position 6: sum:1}̲, mean_age:{avg:"$age"}}}
      )

5.3 $project重构

  • 修改文档结构,修改输出的格式
    _id字段的键使用gender进行替换
    _id:0 不显示_id字段
    count:1 显示count字段
    avg_age:1 显示avg_age字段

    db.stu.aggregate(
    {KaTeX parse error: Expected '}', got 'EOF' at end of input: group:{_id:"gender", count:{KaTeX parse error: Expected 'EOF', got '}' at position 6: sum:1}̲, avg_age:{avg:“KaTeX parse error: Expected 'EOF', got '}' at position 5: age"}̲}}, {project:{_id:0, gender:”$_id", count:1, avg_age:1}}
    )

5.4 $match过滤

  • 选择年龄大于20的学生,观察男性和女性的人数
    db.stu.aggregate(
    {KaTeX parse error: Expected '}', got 'EOF' at end of input: match:{age:{gt:16}}},
    {KaTeX parse error: Expected '}', got 'EOF' at end of input: group:{_id:"gender", count:{KaTeX parse error: Expected 'EOF', got '}' at position 6: sum:1}̲}}, {project:{_id:0, gender:"$_id", count:1}}
    )

  • 选择年龄大于20或者家乡是蒙古或大理的学生,观察男性和女性的人数
    db.stu.aggregate(
    {KaTeX parse error: Expected '}', got 'EOF' at end of input: match:{or:[{age:{KaTeX parse error: Expected 'EOF', got '}' at position 6: gt:16}̲},{hometown:{in:[“蒙古”, “大理”]}}]}},
    {KaTeX parse error: Expected '}', got 'EOF' at end of input: group:{_id:"gender", count:{KaTeX parse error: Expected 'EOF', got '}' at position 6: sum:1}̲}}, {project:{_id:0, gender:"$_id", count:1}}
    )

  • 综合练习:

  • 统计出每个country/province下的userid的数量(同一个userid只统计一次)
    db.dv3.insert({“country” : “china”, “province” : “sh”, “userid” : “a” } )
    db.dv3.insert({  “country” : “china”, “province” : “sh”, “userid” : “b” } )
    db.dv3.insert({  “country” : “china”, “province” : “sh”, “userid” : “a” }  )
    db.dv3.insert({  “country” : “china”, “province” : “sh”, “userid” : “c” } )
    db.dv3.insert({  “country” : “uk”, “province” : “bj”, “userid” : “da” } )
    db.dv3.insert({  “country” : “china”, “province” : “bj”, “userid” : “fa” }  )

  • 所有字段进行分组,可以达到去重的效果,上面第一行于第三行数据相同
    db.dv3.aggregate(
    {KaTeX parse error: Expected '}', got 'EOF' at end of input: …{_id:{country:"country", province:“ p r o v i n c e " , u s e r i d : " province", userid:" province",userid:"userid”}}}
    )

  • 上面去重后的结果继续按照国家和省份进行分组,然后统计每个分组的和

  • 第一次分组后第二次分组,第二次分组使用第一次的分组的_id

  • 分组后的结果重整结构
    db.dv3.aggregate(
    {KaTeX parse error: Expected '}', got 'EOF' at end of input: …{_id:{country:"country", province:“ p r o v i n c e " , u s e r i d : " province", userid:" province",userid:"userid”}}},
    {KaTeX parse error: Expected '}', got 'EOF' at end of input: …{_id:{country:"_id.country", province:“KaTeX parse error: Expected 'EOF', got '}' at position 14: _id.province"}̲, count:{sum:1}}},
    {KaTeX parse error: Expected '}', got 'EOF' at end of input: …ject:{country:"_id.country”, province:"$_id.province", count:1, _id:0}}
    )

5.5 sort排序,skip,limit

  • 学生按年龄升序排列
    db.stu.aggregate(
    {$sort:{age:1}}
    )

  • 学生按性别分组,统计个数,然后按个数降序排列
    db.stu.aggregate(
    {KaTeX parse error: Expected '}', got 'EOF' at end of input: group:{_id:"gender", count:{KaTeX parse error: Expected 'EOF', got '}' at position 6: sum:1}̲}}, {sort:{count:-1}}
    )

  • skip和limit

    • 先跳过两个,然后选定两个
      db.stu.aggregate({KaTeX parse error: Expected 'EOF', got '}' at position 7: skip:2}̲,{limit:2})

5.6 unwind拆分

  • 将⽂档中的某⼀个数组类型字段拆分成多条, 每条包含数组中的⼀个值

  • 语法:db.集合名称.aggregate({ u n w i n d : ′ unwind:' unwind:字段名称’})

    db.t2.insert({_id:1,item:‘t-shirt’,size:[‘S’,‘M’,‘L’]})
    db.t2.aggregate({ u n w i n d : ′ unwind:' unwind:size’})
    结果如下:
    { “_id” : 1, “item” : “t-shirt”, “size” : “S” }
    { “_id” : 1, “item” : “t-shirt”, “size” : “M” }
    { “_id” : 1, “item” : “t-shirt”, “size” : “L” }

  • 字段unwind拆分后,统计长度

    • 插入数据
      db.t3.insert({username:“Alex”, tags:[“C+”, “Java”, “Python”]})
    • 拆分tags,统计拆分后的文档个数
      db.t3.aggregate({KaTeX parse error: Expected 'EOF', got '}' at position 24: …sername:"Alex"}}̲, {unwind:"KaTeX parse error: Expected 'EOF', got '}' at position 6: tags"}̲, {group:{_id:null, sum:{$sum:1}}})
    • 先匹配到用户,然后对tags进行拆分,然后按null(不指定字段,所有文档分组)分组,然后统计分组的个数

6 创建索引

  • 先插入数据,使用js语法
    for(i=0;i<10000;i++){db.t12.insert({name:“test”+i,age:i})}
    数据较多,插入较慢,一分钟左右
    查看数据条数
    db.t12.find().count()

  • 查找数据,并查看耗费时间

    db.t12.find().count()
    100000
    db.t12.find({name:“test30000”})
    { “_id” : ObjectId(“5cf8d888e1d09b780e764cd9”), “name” : “test30000”, “age” : 30000 }
    db.t12.find({age:30000}).explain(‘executionStats’)
    {…
    “executionStats” : {
    “executionSuccess” : true,
    “nReturned” : 1,
    “executionTimeMillis” : 82,
    “totalKeysExamined” : 0,
    “totalDocsExamined” : 100000,

    }
    上面花费时间82ms

  • 建立索引之后对比:
    语法:db.集合.ensureIndex({要建立索引的字段:1}),1表示升序, -1表示降序
    具体操作:
    db.t12.ensureIndex({name:1})
    {
    “createdCollectionAutomatically” : false,
    “numIndexesBefore” : 1,
    “numIndexesAfter” : 2,
    “ok” : 1
    }
    db.t12.find({name:“test30000”}).explain(‘executionStats’)
    “inputStage” : {
    “stage” : “IXSCAN”,
    “nReturned” : 1,
    “executionTimeMillisEstimate” : 0,
    “works” : 2,
    建立索引后查找时间0ms

  • 查看索引
    db.t12.getIndexes()
    [
    {
    “v” : 2,
    “key” : {
    “_id” : 1
    },
    “name” : “id”,
    “ns” : “test.t12”
    },
    {
    “v” : 2,
    “key” : {
    “name” : 1
    },
    “name” : “name_1”,
    “ns” : “test.t12”
    }
    ]
    上面结果中有两个字典,key就是创建索引的字段
    数据库默认都会以_id字段创建默认索引,默认也是升序
    “name” : 1 就是我们刚刚给name字段创建的索引,创建索引后查询速度明显变快

  • 删除索引:
    db.t12.dropIndex(‘索引名称’)
    db.t12.dropIndex({name:1})
    { “nIndexesWas” : 2, “ok” : 1 }
    删除之后就只有一个默认索引了

  • 在默认情况下创建的索引均不是唯一索引。
    创建唯一索引(可以对数据进行去重,name字段相同的但是只会创建一个索引,自动排除重复的):
    db.t12.ensureIndex({“name”:1},{“unique”:true})
    创建唯一索引并消除重复:
    db.t12.ensureIndex({“name”:1},{“unique”:true,“dropDups”:true})  
    建立联合索引(什么时候需要联合索引):
    db.t12.ensureIndex({name:1,age:1})

  • 爬虫数据去重

    • 使用数据库建立的关键字段(一个或者多个)的唯一索引进行去重

    • URL地址对应数据不会变的情况,URL地址能够唯一判别一条数据的

      • 使用场景:
        URL地址持久化存储在redis集合中,具体步骤:
        拿到URL地址,判断url是否在redis的url集合中
        存在:说明url已经请求过,不再请求
        不存在:url没请求过,请求,同时存储url到该集合中
      • 布隆过滤器
        位操作,将url地址通过算法转换为对应的位置
    • 根据数据本身进行去重

      • 选择特定的字段,使用加密算法(md5,sha1)将字段进行加密,生成字符串
      • 后续新来一条数据,同样的方法进行加密,如果得到的字符串在redis集合中
      • 说明存在,对数据更新,如果不存在,则直接插入该数据

7 数据库备份与恢复

  • 启动本地的mongodb数据库,不需要使用mongo连接数据库

  • 直接启动后使用备份和恢复命令即可对mongodb数据库中所有的dbs进行备份操作

  • 要想将其他数据恢复早mongodb中,也是在该级操作

  • 数据备份:
    参考教程:http://www.baidu.com/link?url=I_GAWYpj6q4l_P4fmTfwd8CxCokr0sFvaZB7yhXT4vG-9BEx1pyXus1DocoxqogW7jUZ_7XbMunaCTlGDIk2S5gSQid5YE1Kd-WTR_YEvdq
    备份的语法:
    mongodump -h dbhost -d dbname -o dbdirectory
    -h: 服务器地址, 也可以指定端⼝号
    -d: 需要备份的数据库名称
    -o: 备份的数据存放位置, 此⽬录中存放着备份出来的数据
    -使用mongo连接数据库,可以看到该数据库的地址和端口号

    C:\WINDOWS\system32>net start mongodb
    请求的服务已经启动。

    请键入 NET HELPMSG 2182 以获得更多的帮助。
    C:\WINDOWS\system32>mongo
    MongoDB shell version v4.0.7
    connecting to: mongodb://127.0.0.1:27017/?gssapiServiceName=mongodb
    Implicit session: session { “id” : UUID(“dd815f12-50ec-499d-a162-b5ee7f3003d5”) }
    MongoDB server version: 4.0.7

    exit
    bye

    备份test数据库到H盘的文件夹中:
    mongodump -h 127.0.0.1:27017 -d test -o H:\mongodb\mongobeifen

    C:\WINDOWS\system32>mongodump -h 127.0.0.1:27017 -d test -o H:\mongodb\mongobeifen
    2019-06-09T13:38:50.248+0800 writing test.t12 to
    2019-06-09T13:38:50.338+0800 writing test.stu to
    2019-06-09T13:38:50.339+0800 writing test.dv3 to
    2019-06-09T13:38:50.339+0800 writing test.test1000 to
    2019-06-09T13:38:50.343+0800 done dumping test.stu (7 documents)
    2019-06-09T13:38:50.344+0800 writing test.t3 to
    2019-06-09T13:38:50.347+0800 done dumping test.dv3 (6 documents)
    2019-06-09T13:38:50.348+0800 done dumping test.test1000 (4 documents)
    2019-06-09T13:38:50.349+0800 done dumping test.t3 (1 document)
    2019-06-09T13:38:50.916+0800 done dumping test.t12 (100000 documents)

  • 数据恢复
    恢复语法:
    mongorestore -h dbhost -d dbname --dir dbdirectory
    -h: 服务器地址
    -d: 需要恢复的数据库实例
    –dir: 备份数据所在位置

    mongorestore -h 127.0.0.1:27017 -d douban --dir H:\mongodb\mongobeifen\douban

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值