aggregate() 方法实现聚合函数
文章目录

Mongoose: aggregate() 方法实现聚合函数

需求描述

首先我有一个 Item 的 collection:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
type Item {
_id: String
itemname: String!
itemid: String!
itemtype: String!
parent_id: String
}


///////////////////
/// 主要是下面这一些部分

type Query {
getItemSummary: ItemSummaryResponse
}
type ItemSummaryResponse{
data: [ItemSummary]
success: Boolean
}
type ItemSummary{
_id: String
count: Int
}

gql 端调用的方法:

1
2
3
4
5
6
7
8
9
{
getItemSummary {
data{
_id
count
}
success
}
}

然按照其中的类别 (itemtype) 进行总计:

那么实际上在后台 mongoose 里面需要这么写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
getItemSummary: root => Item.aggregate([
{
$group: {
_id: '$itemtype',
count: {
$sum: 1,
},
},
},
]).then((res) => {
if (res === null) {
return { success: 0, errors: ['sadfsdfsdf'] };
}

return ({
success: 1,
errors: [],
data: res,
});
}),

聚合函数 aggregate() 的使用

首先写明按照哪个 field 进行聚合

1
2
3
4
5
6
7
8
$group: {
_id: '$itemtype',
// 这个地方比较重要,首先左边一定要写成 _id, 最后在前端通过 gql 取的时候也是写 _id
// 另外重要是这个 key 的值是 $itemtype, 说明根据 itemtype 进行 group, 直接写 $ + fieldname 即可
count: {
$sum: 1,
},
},

因为 $group 里面对应需要聚合操作的列必须写成 _id, 否则会出现 The field 'xxx' must be an accumulator object 的报错信息

聚合管道

管道在Unix和Linux中一般用于将当前命令的输出结果作为下一个命令的参数。

基本上就是逐个执行聚合方法里面的方法.

上方的聚合函数仅仅执行了对一个 field 的聚合:

1
2
3
Item.aggregate([
{$group: {_id: '$itemtype',count: {$sum: 1}}},
])

但是实际上可以在这些操作之前之后加更多的操作.

比如想要将,70分到90分之间的数据先筛选出来再进行 group:

1
2
3
4
db.articles.aggregate([
{ $match: { score: { $gt: 70, $lte: 90 } } },
{ $group: { _id: null, count: { $sum: 1 } } }
]);

常用的几个操作

  • $project:修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。
  • $match:用于过滤数据,只输出符合条件的文档。使用MongoDB的标准查询操作。
  • $limit:用来限制MongoDB聚合管道返回的文档数。
  • $skip:在聚合管道中跳过指定数量的文档,并返回余下的文档。
  • $unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。
  • $group:将集合中的文档分组,可用于统计结果。
  • $sort:将输入文档排序后输出。
  • $geoNear:输出接近某一地理位置的有序文档。

实例

$project 实例

0 为不显示,1为显示,默认情况下 _id 字段是 1

1
2
3
4
5
6
7
8
9
10
11
12
db.articles.aggregate({
$project: {
_id: 0,
title: 1,
by_user: 1,
}
});

// 返回
{ "title" : "MongoDB Overview", "by_user" : "runoob.com" }
{ "title" : "NoSQL Overview", "by_user" : "runoob.com" }
{ "title" : "Neo4j Overview", "by_user" : "Neo4j" }

$match 实例

$match 用于获取分数大于70小于或等于90记录,然后将符合条件的记录送到下一阶段$group管道操作符进行处理。

1
2
3
4
5
6
7
db.articles.aggregate([
{ $match: { score: { $gt: 70, $lte: 90 } } },
{ $group: { _id: null, count: { $sum: 1 } } }
]);

// 返回
{ "_id" : null, "count" : 1 }

$skip 实例

经过 $skip 管道操作符处理后,前2个文档被”过滤”掉。

1
db.col_1.aggregate({ $skip: 2 });

参考文献

https://www.jianshu.com/p/baea1bce6de3