当前位置:网站首页 / 数据库 / 正文

[AY-Mongo 3.x]写给自己的MongoDB笔记-聚合操作,mapreduce,group,游标等【1/3】[6]

时间:2015年11月04日 | 作者 : aaronyang | 分类 : 数据库 | 浏览: 1664次 | 评论 0

2015年11月4日 ====== AYUI www.ayjs.net AY 杨洋原创编写,请不要转载谢谢======

Count求复合条件的数量

db.students.count({"name":/^a/})

blob.png


distinct

查询年龄,不包括重复

db.students.distinct("age")

blob.png

条件式的distinct

db.students.distinct("age",{"name":{$in:["aaronyang","ab","ac","ad"]}})

blob.png

我没找到怎样像rdbms中那样,还可以显示其他列,以后会了再补上吧

使用runCommand执行distinct,必须指定集合名,在这里我们是处理students的

blob.png

2015年11月4日 ====== AYUI www.ayjs.net AY 杨洋原创编写,请不要转载谢谢======

Group 算是比较复杂的一个

①列出基本格式

db.students.group({


})


②属性讲解

 key:如果是多个字段,可以为{"f1":true,"f2":true}

key类似 rdbms中的 group by key中的key,这里我按照age分组

db.students.group({
    "key":{"age":true}  
})

initial 为每组准备个默认的对象,在这里names就是组名,名字自己取

db.students.group({
"key":{"age":true},
"initial":{"names":[]}
})

$reduce: 这个函数的第一个参数是当前的文档对象,第二个参数是上一次function操作的 组名(还句话就是names这个数组,自己定义的),第一次为initial中的{”names“:[]}。有多少个文档, $reduce就会调用多少次

下面的$reduce是可以不加$的,双引号在只有一个值的时候,不是复合值那种就可加可不加

db.students.group({
"key":{"age":true},
"initial":{"names":[]},
"$reduce":function(cur,prev){
	 prev.names.push(cur.name)
}
})

blob.png

condition 过滤条件,只要name是a开头的对象来进行聚合操作

db.students.group({
"key":{"age":true},
"initial":{"names":[]},
"$reduce":function(cur,prev){
	 prev.names.push(cur.name)
},
condition:{"name":/^a/}
})

blob.png

2015年11月4日 ====== AYUI www.ayjs.net AY 杨洋原创编写,请不要转载谢谢======

finalize:这是个函数,每一组文档执行完后,都会触发此方法,类似C#的析构函数

我们增加count值

db.students.group({
"key":{"age":true},
"initial":{"names":[]},
"$reduce":function(cur,prev){
	 prev.names.push(cur.name)
},
condition:{"name":/^a/},
finalize:function(cur){
cur.count=cur.names.length;
}
})

blob.png

(关于aggregate这个方法的group暂时不在这里讲)



Map-Reduce

Map-Reduce是一种计算模型,简单的说就是将大批量的工作(数据)分解(MAP)执行,然后再将结果合并成最终结果(REDUCE)。

MongoDB提供的Map-Reduce非常灵活,对于大规模数据分析也相当实用

blob.png

按照我个人的想法理解就是,就是db.students.mapReduce(map函数,reduce处理map传来的键值队的函数,options其他参数设置)

我先放一张当前库中的数据

blob.png

db.students.mapReduce( 
   function() { emit(this.age,1); }, 
   function(key, values) {return Array.sum(values)}, 
      {  
         query:{name:/^a/},  
         out:"students_total" 
      }
)

这里map函数是

function() { emit(this.age,1); }

我按照age分组,每次传的value都是1

reduce函数

 function(key, values) {return Array.sum(values)}

这里每次values都是1,每次累加,也就是,按照age分组后,1条记录,就是1,两条记录就是2

第三个参数对象

 {  
         query:{name:/^a/},  
         out:"students_total" 
      }

这里query为查询过滤参数,out为临时集合的名字,统计结果存放集合 (不指定则使用临时集合,在客户端断开后自动删除)

后面的sort参数,为排序,limit为限制显示多少个。


OK,查询运行时候,map会遍历集合中的每条文档,符合query,就reduce一次,

blob.png

结果表明,共有9(input值)个符合查询条件(name:/^a/)的文档, 在map函数中生成了9个键值对文档,最后使用reduce函数将相同的键值分为2(reduce值)组

这个reduce感觉也是结果集中一个文档一共有多少个列(在mongo叫键/Key吧)

result:储存结果的collection的名字,这是个临时集合,MapReduce的连接关闭后自动就被删除了。

timeMillis:执行花费的时间,毫秒为单位

input:满足条件被发送到map函数的文档个数

emit:在map函数中emit被调用的次数,也就是所有集合中的数据总量

ouput:结果集合中的文档个数(count对调试非常有帮助)

ok:是否成功,成功为1

err:如果失败,这里可以有失败原因,不过从经验上来看,原因比较模糊,作用不大

我们可以使用在mapReduce(...).find()方法查看结果集,例如10岁的有1个,22岁的有1个,23岁的有3个...

blob.png

value的和1+1+3+1+1+2=9就是 我在map中每次传进去1的每组累加的结果,这里正好每次是1,也就是input值了


此时输入  db.students_total.find()可以查询临时集合的结果集

blob.png



游标 Cursor

类似C#延迟执行

var cursor=db.students.find();这个时候是没有执行的。

调用完find后,此时Shell并不会去真正地访问数据库,而是等待开始要求获得结果的时候才向数据库发送查询请求!我们此时可以对这个游标进行各种设置,然后调用游标的hashNext()或next()方法,这样就会真正访问数据库,这是一个懒加载的过程


这里我还是重新创建一批数据

for(var i=0; i<100; i++){  
   db.scores.insert({"point" : i});  
}

blob.png

print这些值,当调用了游标的hasNext()或者next此时就去数据库拿值了。

var cursor = db.scores.find();  
while(cursor.hasNext()){  
  var doc = cursor.next();  
  print(doc.point);
 };

blob.png

blob.png

当调用cursor.hasNext()时,查询被发往数据库,默认会返回前100条文档或者前4M的数据(两者之中较小的),这样下次next或hasNext都是本地调用了!当这组数据被遍历完毕,hasNext会导致再次去访问数据库,直到所有结果被返回!

这里有3个函数可以在处理游标时使用:limit、skip、sort

下面展示个分页,就写了2个,主要通过skip跳过,不过都是先find(),然后执行sort(大于0升序,小于0降序),然后skip,最后limit返回

db.scores.find().skip(0).limit(10).sort({"point":1}); 
db.scores.find().skip(10).limit(10).sort({"point":1});

blob.png

mongo中sort的排序顺序(升序)

(1):最小值

(2):null

(3):数字(整型,长整型,双精度)

(4):字符串

(5):对象/文档

(6):数组

(7):二进制数据

(8):对象ID

(9):布尔值

(10):日期型

(11):时间戳

(12):正则表达式

(13):最大值


skip要避免大量数据跳过

1. 将分页的处理放在应用层,即将数据全部查出,然后在应用层处理分页显示!这就是通常所说的伪分页!

2. 如果分页必须在数据库端进行,这通常是数据量太大的情况!这时,我们先尝试使用skip操作,如果出现性能瓶颈,我们只能根据一个排序键,在获取下页数据时,首先根据上一页最后一个文档中该键的值来查询文档,最后排序截取即可!这样就可以避免使用skip!


查询分为普通查询和包装查询

普通 db.students.find({"name":/^a/}).sort({"age":1})

blob.png

包装查询  db.students.find({"$query":{"name":/^a/},"$orderby":{"age":1}})

blob.png

我们的所有查询在发送到数据库端时,都被提前转换成了包装形式!包装形式就是额外使用了一些键,如上述的"$query","$orderby"。我们还有如下一些有用的键可用:

1. $maxscan : integer  指定查询时最多扫描文档的数量

2. $min : document   查询的开始条件

3. $max : document   查询的结束条件

4. $hint : document  指定服务器使用哪些索引进行查询

5. $explain : boolean 获取查询细节,如用到的索引,结果数量,耗时等,类似于关系数据库这边查看执行计划。并不会真正执行查询

6. $snapshot : boolean 确保查询的结果是在查询执行那一刻的一致快照!这个在后面还会提到!



我们从MongoDB中获取到数据后,通常会执行这种操作:对文档进行处理后,即时地更新到数据库中!这时对于大量文档的情况有可能产生一个问题,我来描述一下:前面提到了,我们从数据库端调用游标的hasNext时,数据库默认会返回100条文档给我们,我们开始操作。假设对于一个文档,我们增大了其大小,并且超过了MongoDB为文档设置的预留区域,这时我们将这条文档更新到数据库中,数据库没法将其放置在其原始位置上,只能将其移动,通常会移动到集合末尾!这样我们再次获取文档时,有可能又得到这条以被修改的文档!!

应对这个问题,我们的方法就是对查询结果进行快照!如果使用了上面提到的“$snapshop”选项,查询就是针对不变的集合视图运行的!这点我们只是描述一下,实际情况中可以不用担心了,因为MongoDB中,所有返回一组的查询实际都进行了快照!


游标测试:

var results=db.students.find({"name":/^a/}).sort({"age":1});

回车,然后

results 回车

blob.png

然后forEach没有值了,因为游标到末尾了

blob.png

我们重置游标

var results=db.students.find({"name":/^a/}).sort({"age":1});

回车,然后

results.forEach(function(o){

print(o.name);

})

回车

最后

results

回车

blob.png

类似 mssql中的 with的临时表用法,用一次就没了。



2015年11月4日 ====== AYUI       www.ayjs.net      AY         杨洋原创编写,请不要转载谢谢======










推荐您阅读更多有关于“mongodb,”的文章

猜你喜欢

额 本文暂时没人评论 来添加一个吧

发表评论

必填

选填

选填

必填

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

  查看权限

合肥科大智能常年招聘.NET,Java,Web前端,有想找想换工作的私聊我AY唯一QQ:875556003和AY交流

抖音号:wpfui,可以看到我的很多作品效果

AYUI8社区版Github地址:前往获取

作者:杨洋(AaronYang简称AY,安徽六安人)目前是个人,还没公司AY唯一QQ:875556003和AY交流

高中学历,2015年1月17日开始,兴趣学习研究WPF,目前工作繁忙,不接任何活

声明:AYUI7个人与商用免费,源码可购买。部分DEMO不免费.AY主要靠卖技术服务挣钱

不是从我处购买的ayui7源码,我不提供任何技术服务,如果你举报从哪里买的,我可以帮你转正为我的客户,并送demo

查看捐赠

AYUI7.X MVC教程 更新如下:

第一课 第二课 程序加密教程

vs2015 企业版密钥HM6NR-QXX7C-DFW2Y-8B82K-WTYJV

vs2017 企业版密钥NJVYC-BMHX2-G77MM-4XJMR-6Q8QF

标签列表