项目中,需要对mongo中某个集合进行分组汇总,集合主要包含下面几个字段
// 日期
private Integer date;
// 账号id
private Long accountId;
// 标题
private String title;
// 状态
private Integer status;
// 状态🐴
private String statusCode;
// 数量
private Integer count;
集合主要包含下面两个索引
{
"v" : 2,
"key" : {
"date" : -1.0,
"accountId" : 1.0,
"status" : 1.0
},
"name" : "date_-1_accountId_1_status_1",
"background" : true
},
{
"v" : 2,
"key" : {
"date" : -1.0,
"accountId" : 1.0,
"title" : 1.0
},
"name" : "date_-1_accountId_1_title_1",
"background" : true
},
现在想对指定日期、指定账号下的数据不同标题下面的数量进行汇总,刚开始使用下面代码:
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.match(Criteria.where("date")
.is(date).and("accountId").is(accountId)),
Aggregation.group("title", "statusCode")
.sum("count").as("totalCount"));
但是实际在测试的时候,发现速度比较慢(数据库千万级),通过查看mongo日志,发现走的是date_-1_accountId_1_status_1索引,并没有使用date_-1_accountId_1_title_1索引。
于是查询mongo官方文档Aggregation Pipeline — MongoDB Manual,怎样才能使用group中的字段索引,发现了有如下说明:
$group
The $group stage can sometimes use an index to find the first document in each group if all of the following criteria are met:
The $group stage is preceded by a $sort stage that sorts the field to group by,
There is an index on the grouped field which matches the sort order and
The only accumulator used in the $group stage is $first
See Optimization to Return the First Document of Each Group for an example.
具体意思大家自己翻译,我理解的意思是,将分组group的列进行排序一下,应用到我们这个场景,就是将title字段排序一下,就可能走date_-1_accountId_1_title_1索引,聚合速度可能就更快了。
以上只是猜想,实践如下:
Sort sort = new Sort(Sort.Direction.ASC, "title");
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.match(Criteria.where("date")
.is(date).and("accountId").is(accountId)),
Aggregation.sort(sort),
Aggregation.group("title").sum("count").as("totalCount")
);
测试结果,查看mongo日志,确实走了date_-1_accountId_1_title_1索引,聚合速度相对之前也快了不少。
总结
mongo很多知识点在网上搜到的都是比较基础,很多都是告诉你Aggregation聚合基本用法,一些复杂一点的用法,还是得自己去看官方文档比较靠谱,之前遇到的几个MongoDB问题,都是通过查看官方文档解决的,官方文档也比较详细。