mongoose使用aggregate实现按照日期分组统计

需求

统计最近N天的新增用户数量

分析

很幸运,MongoDB提供了聚合函数aggregate来完成这个任务。

实现

1. Model

1
2
3
{"_id" : 1, "createdTime" : ISODate("2017-03-07T06:40:58.337+0000"), ...},
{"_id" : 2, "createdTime" : ISODate("2017-03-08T06:40:58.337+0000"), ...},
{"_id" : 3, "createdTime" : ISODate("2017-03-09T06:40:58.337+0000"), ...}

2. 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
db.users.aggregate(
// Pipeline
[
// 符合这个条件的文档才被统计
{
$match: {
"createdTime": { $gt: ISODate("2017-01-17T23:41:04.372+0000") }
}
},
// 定义一些字段,给后面的处理使用,排除、重命名和显示字段
{
$project: {
// 时区数据校准,8小时换算成毫秒数为8*60*60*1000=288000后分割成YYYY-MM-DD日期格式便于分组
day1 : {$substr: [{"$add":["$createdTime", 28800000]}, 0, 10] }
day2: { year: { $year: "$createdTime" }, month: { $month: "$createdTime" }, day: { $dayOfMonth: "$createdTime"} }, // 因为MongoDB的时区,直接使用这种方法的日期是不正确的
}
},
// 按照给定表达式组合结果
{
$group: {
_id: "$day1", // 将_id设置为day数据
totalCount:{$sum: 1}, // 统计count, 每条数据+1
}
},
// 排序
{
$sort: {
_id: 1
}
},
]
);

3. 说明

  • $match : 查询,需要同find()一样的参数
  • $project:包含、排除、重命名和显示字段
  • $group:按照给定表达式组合结果
  • $sort:按照给定的字段排序结果
  • $sum:总结从集合中的所有文件所定义的值。后面可以是一个字段,表示对这个字段累加,如果是常数,表示每次增加的数值。

4. 返回结果

1
2
3
4
5
6
7
8
9
10
11
12
[{
"_id": "2017-02-24",
"totalCount": 1
},
{
"_id": "2017-03-07",
"totalCount": 1
},
{
"_id": "2017-03-16",
"totalCount": 1
}]

5. 效果

环境

  • mongoose ^4.7.5
  • Node.js ^7.0.0
  • DEBUG:
    • Studio 3T for MongoDB

参考