之前在看mongo的书时,看到了聚合这章。其中谈到了group这个功能,其实正如书中所说,mongodb中的group和sql中的group by是很相似的,但我自我分析,可能由于mongo中的group的使用形式不同,而且使用的是js 语法,所以导致咋一看上去不明白这个group怎么用。下面通过具体的一个例子来详细说明mongo的group用法。
我们平常所用的博客,每天会有很多人发博客,每篇文章中都有多个标签,现在要找出每天最热点的标签。首先,我们可以按天分组,将每天每一标签的计数给统计出来。
我们可以简单地假设集合中文档的结构如下:
1 {“title” : “java sun”, “author” : “jk”, “day” : “2012-12-14”, “tags” : [“java”, “nosql”, “spring”]} 2 3 {“title” : “ssh2的整合”, “author” : “cj”, “day” : “2012-5-10”, “tags” : [“struts 2”, “hibernate ”, “spring”]} 4 5 {“title” : “c#的高级用法”, “author” : “zt”, “day” : “2012-4-3”, “tags” : [“c#”, “sql”]} 6 7 {“title” : “php mongo”, “author” : “lx”, “day” : “2012-12-14”, “tags” : [“php”, “nosql”, “mongo”]} 8 9 …
mongo代码如下:
1 >db.posts.group({ 2 3 … “key” : {“day” : true}, 4 5 … “initial” : {“tags” : {}}, 6 7 … “$reduce” : function (doc, prev) { 8 9 … for (i in doc.tags) { 10 11 … if (doc.tags[i] in prev.tags) { 12 13 … prev.tags[doc.tags[i]]++; 14 15 … } 16 17 … else 18 19 … { 20 21 … prev.tags[doc.tags[i]] = 1; 22 23 … } 24 25 … } 26 27 … } 28 29 })
现在我们来逐行分析上述的代码意思。
1 “key” : {“day” : true}
“key”表示集合数据分组的依据。这里我们指定了“day”键,那么会根据集合文档中的发布博客时间来进行分组。那有人会问,那个“true”有什么意义?如果指定了{“day” : true},那么在分组的结果中就会显示每组“day”的键值。
1 “initial” : {“tags” : {}}
这个大家可能会迷惑,initial是初始化的意思,分组为什么还要初始化呢?sql好像
此文来自: 马开东博客 转载请注明出处 网址: http://www.makaidong.com
也没有类似的概念啊。这个就是两者不同的地方了。这里是为了初始化累加器的键值,我们可以把这个所谓的“累加器”当作一个文档,这个文档中存放是的在分组 开发过程 中收集、计算出的信息,不一定是集合文档中的原信息,这里需要注意。“tags”表示每个分组中第一个文档对应调用“$reduce”指定函数时的参数初始化,后续该分组的文档对应调用“$reduce”指定函数时,会不断“累加”,保留住每次对“tags”所做的更新结果。有人可能不理解上面一句在讲什么,可以结合下面的解释来理解。
1 “$reduce” : function(doc, prev) { … }
看到这里可能有些人就彻底崩溃了,我也是,不就分个组吗,怎么把函数都整出来,还是js 的。其实我们可以把这里的函数理解为分组开发过程 ,在分组的开发过程 中,我们又人为地添加了一些操作,比如信息收集、汇总、统计等等。“doc”代表分组开发过程 中的每一个集合中的文档,而“prev”则代表“累加器文档”的累加状态,当一个分组的组员划分完毕时,这个“prev”文档中的键值对的最终状态就是我们想要的结果。这里需要注意函数体中的“prev.tags”和“doc.tags”是不同的,不信我们可以看结果。
按照上面的代码分类后得到的结果如下所示:
1 {“day” : “2012-12-14”, “tags” : {“java” : 1, “nosql” : 2, “spring” : 1, “mongo” : 1}} 2 3 {“day” : “2012-5-10”, “tags” : {“struts 2” : 1, “hibernate ” : 1, “spring” : 1}} 4 5 {“day” : “2012-4-3”, “tags” : {“c#” : 1, “sql” : 1}}
看出不同了吗?上面的结果中,“tags”键的值是一个内嵌文档,而这对应的就是“pre.tags”。“doc.tags”表示的原集合文档中“tags”键的多值数组。
我们要找的是每天最热门的标签,显然我们上面的结果还有些多余的信息,那么就让我们使用“finalize”键来进行精简吧,还是先看代码。
1 >db.posts.group({ 2 3 … “key” : {“day” : true}, 4 5 … “initial” : {“tags” : {}}, 6 7 … “$reduce” : function (doc, prev) { 8 9 … for (i in doc.tags) { 10 11 … if (doc.tags[i] in prev.tags) { 12 13 … prev.tags[doc.tags[i]]++; 14 15 … } 16 17 … else 18 19 … { 20 21 … prev.tags[doc.tags[i]] = 1; 22 23 … } 24 25 … } 26 27 … }, 28 29 … “finalize” : function (prev) { 30 31 … var mostpopular = 0; 32 33 … for (i in prev.tags) { 34 35 … if (prev.tags[i] > mostpopular) { 36 37 … prev.tag = i; 38 39 … mostpopular = prev.tags[i]; 40 41 … } 42 43 … } 44 45 … delete prev.tags; 46 47 … } 48 49 })
“finalize”附带的函数,在每个分组结果传递到客户端之前会被调用一次,从而可以对分组结果进行“修剪”。从上面我们可以看出,原先结果中的“tags”键值给删去了,加上了一个“tag”键值,所以最终的结果如下:
1 {“day” : “2012-12-14”, “tag” : { “nosql”} 2 3 {“day” : “2012-5-10”, “tags” : {“struts 2” : 1}} 4 5 {“day” : “2012-4-3”, “tags” : {“c#” : 1}}
在举个例子,本来我在刚看过上面的那段代码后,想在自己写的示例系统开发——用户管理系统开发中,用php结合group功能实现用户的爱好分类统计,但由于刚开始我也一直处于迷糊状态,所以一直没想出解决办法,今天通过仔细阅读php开发手册的例子,终于实现了这一功能。下面是用户集合中的文档结构:
1 { "_id" : objectid("50f0c0ca323365ec0c000006"), "username" : "大胖", "age" : 23, "birthday" : Iphone 苹果 ios date("1989-10-29t16:00:00z"), "interest " : [ "篮球", "足球", "乒乓球", "高尔夫球" ] } 2 3 { "_id" : objectid("50f35b6f323365f00c000001"), "username" : "六福", "age" : 24, "birthday" : Iphone 苹果 ios date("1988-05-05t15:00:00z"), "interest " : [ "乒乓球", "篮球" ] } 4 5 { "_id" : objectid("50f37257323365ec0c000000"), "username" : "七喜", "age" : 30, "birthday" : Iphone 苹果 ios date("1984-09-30t16:00:00z"), "interest " : [ "足球", "橄榄球" ] } 6 7 …
那么如何用group开发方法 来统计出喜爱篮球的有多少人,喜爱足球的有多少人等信息呢?现在我就用mongo——php驱动开发 提供的api来实现group的功能。有兴趣的人可以根据下面的代码简练出mongo语法的代码。
1 /* 2 3 * 统计爱好分类信息 4 5 */ 6 7 public function groupbyinterest () 8 9 { 10 11 $key = array(); //$key没有指定分组依据,那么所有文档认为属于同一组 12 13 $initial = array('interest s' => array()); 14 15 $reduce = 'function(obj, prev) { 16 17 for (i in obj.interest ) 18 19 { 20 21 if (obj.interest [i] in prev.interest s) 22 23 { 24 25 prev.interest s[obj.interest [i]]++; 26 27 } 28 29 else 30 31 { 32 33 prev.interest s[obj.interest [i]] = 1; 34 35 } 36 37 } 38 39 }'; 40 41 $g = $this->users->group($key, $initial, $reduce); 42 43 return $g['retval']; 44
http://www.cnblogs.com/mxw09/archive/2011/08/31/2161457.html 搜索此文相关文章:关于MongoDB的group用法 此文链接:http://www.makaidong.com/%E5%8D%9A%E5%AE%A2%E5%9B%AD%E7%89%9B/33875.shtml