MongoDB分组group

        MongoDB使用group做聚合,首先必须先选定分组所用到的键,然后MongoDB就会将集合依据选定的键的按照不同值进行分组,最终得到一组文档。

1.先插入测试数据

> for(var i=1; i<20; i++){
... var num=i%6;
... db.test.insert({"_id":i,"name":"user_"+i,"age":num});
... }
> db.test.find()
{ "_id" : 1, "name" : "user_1", "age" : 1 }
{ "_id" : 2, "name" : "user_2", "age" : 2 }
{ "_id" : 3, "name" : "user_3", "age" : 3 }
{ "_id" : 4, "name" : "user_4", "age" : 4 }
{ "_id" : 5, "name" : "user_5", "age" : 5 }
{ "_id" : 6, "name" : "user_6", "age" : 0 }
{ "_id" : 7, "name" : "user_7", "age" : 1 }
{ "_id" : 8, "name" : "user_8", "age" : 2 }
{ "_id" : 9, "name" : "user_9", "age" : 3 }
{ "_id" : 10, "name" : "user_10", "age" : 4 }
{ "_id" : 11, "name" : "user_11", "age" : 5 }
{ "_id" : 12, "name" : "user_12", "age" : 0 }
{ "_id" : 13, "name" : "user_13", "age" : 1 }
{ "_id" : 14, "name" : "user_14", "age" : 2 }
{ "_id" : 15, "name" : "user_15", "age" : 3 }
{ "_id" : 16, "name" : "user_16", "age" : 4 }
{ "_id" : 17, "name" : "user_17", "age" : 5 }
{ "_id" : 18, "name" : "user_18", "age" : 0 }
{ "_id" : 19, "name" : "user_19", "age" : 1 }

2.普通的分组查询:

> db.test.group({key:{age:true}, initial:{num:0}, $reduce:function(doc,prev) {
...prev.num++
...}});
[
        {
                "age" : 1,
                "num" : 4
        },
        {
                "age" : 2,
                "num" : 3
        },
        {
                "age" : 3,
                "num" : 3
        },
        {
                "age" : 4,
                "num" : 3
        },
        {
                "age" : 5,
                "num" : 3
        },
        {
                "age" : 0,
                "num" : 3
        }
]
> db.runCommand({group:
... {
... ns:"test",
... key:{age:true},
... initial:{num:0},
... $reduce:function(doc,prev){
... prev.num++}
... }
... });
{
        "retval" : [
                {
                        "age" : 1,
                        "num" : 4
                },
                {
                        "age" : 2,
                        "num" : 3
                },
                {
                        "age" : 3,
                        "num" : 3
                },
                {
                        "age" : 4,
                        "num" : 3
                },
                {
                        "age" : 5,
                        "num" : 3
                },
                {
                        "age" : 0,
                        "num" : 3
                }
        ],
        "count" : 19,
        "keys" : 6,
        "ok" : 1
}

以上使用group对age进行分组。

ns:指定要分组的集合。

key:指定文档分组依据的键。

initial:每一组reduce()函数调用的初始时间,会作为初始文档传递给后续过程。每一组的所有成员都会使用这个累加器,所有的改变都会保留。

$reduce:每个文档都对用一次该调用。系统会传递两个参数,当前文档和累加器文档。

3.对于age大于2的文档进行分组

> db.test.group({key:{age:true},initial:{num:0},$reduce:function(doc,prev){
... prev.num++
... },
... condition:{age:{$gt:2}}
... });
[
        {
                "age" : 3,
                "num" : 3
        },
        {
                "age" : 4,
                "num" : 3
        },
        {
                "age" : 5,
                "num" : 3
        }
]
> db.runCommand({group:
... {
... ns:"test",
... key:{age:true},
... initial:{num:0},
... $reduce:function(doc,prev){
... prev.num++},
... condition:{age:{$gt:2}}
... }
... });
{
        "retval" : [
                {
                        "age" : 3,
                        "num" : 3
                },
                {
                        "age" : 4,
                        "num" : 3
                },
                {
                        "age" : 5,
                        "num" : 3
                }
        ],
        "count" : 9,
        "keys" : 3,
        "ok" : 1
}
>

以上代码使用group对于age大于2的文档进行分组。


4.group分组和$where查询结合

> db.test.group({key:{age:true},initial:{num:0},$reduce:function(doc,prev){
... prev.num++
... },
... condition:{$where:function(){
... return this.age>2;
... }
... }
... });
[
        {
                "age" : 3,
                "num" : 3
        },
        {
                "age" : 4,
                "num" : 3
        },
        {
                "age" : 5,
                "num" : 3
        }
]
>

5.使用完成器

完成器(Finalize)用以精简从数据库传到用户数据。特别需要注意,group命令的输出一定要放在耽搁数据库中响应:

> db.test.group({$keyf:function(doc){return {age:doc.age};},initial:{num:0},$reduce:function(doc,prev){
... prev.num++
... },
... finalize: function(doc){ doc.count=doc.num;delete doc.num; }
... });
[
        {
                "age" : 1,
                "count" : 4
        },
        {
                "age" : 2,
                "count" : 3
        },
        {
                "age" : 3,
                "count" : 3
        },
        {
                "age" : 4,
                "count" : 3
        },
        {
                "age" : 5,
                "count" : 3
        },
        {
                "age" : 0,
                "count" : 3
        }
]
> db.runCommand({group:
... {
... ns:"test",
... $keyf:function(doc){return {age:doc.age};},
... initial:{num:0},
... $reduce:function(doc,prev){
... prev.num++},
... finalize: function(doc){ doc.count=doc.num;delete doc.num; }
... }
... });
{
        "retval" : [
                {
                        "age" : 1,
                        "count" : 4
                },
                {
                        "age" : 2,
                        "count" : 3
                },
                {
                        "age" : 3,
                        "count" : 3
                },
                {
                        "age" : 4,
                        "count" : 3
                },
                {
                        "age" : 5,
                        "count" : 3
                },
                {
                        "age" : 0,
                        "count" : 3
                }
        ],
        "count" : 19,
        "keys" : 6,
        "ok" : 1
}
>

本例通过完成器精简版从数据库传到用户的数据,注意,group命令的输出一定要放在耽搁数据响应中。

5.将函数作为键使用

有时分组所依据的条件非常复杂,不仅是一个键,还有可能是函数,定义函数就要用到$keyf(注意不是key)

> db.test.group({$keyf:function(doc){return {age:doc.age};},initial:{num:0},$reduce:function(doc,prev){
... prev.num++
... }
... });
[
        {
                "age" : 1,
                "num" : 4
        },
        {
                "age" : 2,
                "num" : 3
        },
        {
                "age" : 3,
                "num" : 3
        },
        {
                "age" : 4,
                "num" : 3
        },
        {
                "age" : 5,
                "num" : 3
        },
        {
                "age" : 0,
                "num" : 3
        }
]
> db.runCommand({group:
... {
... ns:"test",
... $keyf:function(doc){return {age:doc.age};},
... initial:{num:0},
... $reduce:function(doc,prev){
... prev.num++}
... }
... });
{
        "retval" : [
                {
                        "age" : 1,
                        "num" : 4
                },
                {
                        "age" : 2,
                        "num" : 3
                },
                {
                        "age" : 3,
                        "num" : 3
                },
                {
                        "age" : 4,
                        "num" : 3
                },
                {
                        "age" : 5,
                        "num" : 3
                },
                {
                        "age" : 0,
                        "num" : 3
                }
        ],
        "count" : 19,
        "keys" : 6,
        "ok" : 1
}
>

上述中我们使用$keyf定义一个函数,作为参数传入到group中,作为一个复制的分组依据来完成分组。

参考《深入云计算:MongoDB管理与开发实战详解》

你可能感兴趣的:(MongoDB,NoSql,数据库)