group做的聚合有些复杂。先选定分组所依据的键,此后MongoDB就会将集合依据选定键值的不同分成若干组。然后可以通过聚合每一组内的文档,产生一个结果文档。
和数据库一样group常常用于统计。MongoDB的group还有很多限制,如:返回结果集不能超过16M, group操作不会处理超过10000个唯一键,好像还不能利用索引[不很确定]。
Group大约需要一下几个参数。
1.key:用来分组文档的字段。和keyf两者必须有一个
2.keyf:可以接受一个javascript函数。用来动态的确定分组文档的字段。和key两者必须有一个
3.initial:reduce中使用变量的初始化
4.reduce:执行的reduce函数。函数需要返回值。
5.cond:执行过滤的条件。
6.finallize:在reduce执行完成,结果集返回之前对结果集最终执行的函数。可选的。
下面介绍一个实例:
先插入测试数据:
1
2
3
4
|
for
(var i=1; i<20; i++){
var num=i%6;
db.
test
.insert({_id:i,name:
"user_"
+i,age:num});
}
|
1.普通分组查询
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
db.
test
.group({
key:{age:
true
},
initial:{num:0},
$reduce:
function
(doc,prev){
prev.num++
}
});
db.runCommand({group:
{
ns:
"test"
,
key:{age:
true
},
initial:{num:0},
$reduce:
function
(doc,prev)
{
prev.num++
}
}
});
|
2.筛选后再分组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
db.
test
.group({
key:{age:
true
},
initial:{num:0},
$reduce:
function
(doc,prev)
{
prev.num++
},
condition:{age:{$gt:2}}
});
db.runCommand({group:
{
ns:
"test"
,
key:{age:
true
},
initial:{num:0},
$reduce:
function
(doc,prev)
{
prev.num++},
condition:{age:{$gt:2}}
}
});
|
3、普通的$where查询:
1
2
3
4
|
db.
test
.
find
({$where:
function
(){
return
this.age>2;
}
});
|
group联合$where查询
1
2
3
4
5
6
7
8
9
10
11
|
db.
test
.group({
key:{age:
true
},
initial:{num:0},
$reduce:
function
(doc,prev){
prev.num++
},
condition:{$where:
function
(){
return
this.age>2;
}
}
});
|
4、使用函数返回值分组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
//
注意,$keyf指定的函数一定要返回一个对象
db.
test
.group({
$keyf:
function
(doc){
return
{age:doc.age};},
initial:{num:0},
$reduce:
function
(doc,prev){
prev.num++
}
});
db.runCommand({group:
{
ns:
"test"
,
$keyf:
function
(doc){
return
{age:doc.age};},
initial:{num:0},
$reduce:
function
(doc,prev){
prev.num++}
}
});
|
5.使用终结器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
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; }
});
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; }
}
});
|
有关MapReduce
1
2
3
4
5
6
7
8
9
10
11
12
13
|
//
首先插入测试数据
for
(var i=1;i<21;i++)
{
db.
test
.insert({_id:i,name:
'mm'
+i});
}
//
进行mapreduce
db.runCommand(
{
mapreduce:
'test'
,
map:
function
(){emit(this.name.substr(0,3),this);},
reduce:
function
(key,vals){
return
vals[0];},
//
注意:vals是一个Object对象而不是数组
out:
'wq'
});
|
注意:
1.mapreduce是根据map函数里调用的emit函数的第一个参数来进行分组的
2.仅当根据分组键分组后一个键匹配多个文档,才会将key和文档集合交由reduce函数处理。例如:
1
2
3
4
5
6
7
|
db.runCommand(
{
mapreduce:
'test'
,
map:
function
(){emit(this.name.substr(0,3),this);},
reduce:
function
(key,vals){
return
'wq'
;},
out:
'wq'
});
|
执行mapreduce命令后,再查看wq表数据:
1
2
3
4
5
6
7
8
9
10
11
|
db.wq.
find
()
{
"_id"
:
"mm1"
,
"value"
:
"wq"
}
{
"_id"
:
"mm2"
,
"value"
:
"wq"
}
{
"_id"
:
"mm3"
,
"value"
: {
"_id"
: 3,
"name"
:
"mm3"
} }
{
"_id"
:
"mm4"
,
"value"
: {
"_id"
: 4,
"name"
:
"mm4"
} }
{
"_id"
:
"mm5"
,
"value"
: {
"_id"
: 5,
"name"
:
"mm5"
} }
{
"_id"
:
"mm6"
,
"value"
: {
"_id"
: 6,
"name"
:
"mm6"
} }
{
"_id"
:
"mm7"
,
"value"
: {
"_id"
: 7,
"name"
:
"mm7"
} }
{
"_id"
:
"mm8"
,
"value"
: {
"_id"
: 8,
"name"
:
"mm8"
} }
{
"_id"
:
"mm9"
,
"value"
: {
"_id"
: 9,
"name"
:
"mm9"
} }
|
以上所述就是本文的全部内容了,希望大家能够喜欢。