MongoDB在大集合中按月聚合组-优化管道

MongoDB在大集合中按月聚合组-优化管道,mongodb,Mongodb,我知道在SO之前有人问过这个问题,但我似乎找不到如何在更大的集合中处理聚合分组。我有一组超过1000万条的记录,但我就是没有速度 运行MongoDB V3.2 在模式中有一个字段\uuu createDateUtc(ISODate),我正在尝试以下管道: db.transactions.aggregate([ { $project: { __createDateUtc: 1 } }, { $group

我知道在SO之前有人问过这个问题,但我似乎找不到如何在更大的集合中处理聚合分组。我有一组超过1000万条的记录,但我就是没有速度

运行MongoDB V3.2

在模式中有一个字段
\uuu createDateUtc
(ISODate),我正在尝试以下管道:

db.transactions.aggregate([
    {
        $project: {
            __createDateUtc: 1
        }
    },
    {
        $group: {
            '_id': { $year: '$__createDateUtc' },
            'count': {$sum: 1},
        }
    },
    {
        $limit: 10
    },
])

这将以+20秒的速度运行。能快点吗?这是一个相当简单的管道-所以说真的-在这种情况下有没有其他的策略可以帮助

我用四种不同的方法做了一些基准测试,以获得我想要的结果。结果令人沮丧

同样,模式如下所示:

{
    "_id" : ObjectId("5d665491fd5852755236a5dc"),
    ...
    "__createDateUtc" : ISODate("2019-08-28T10:16:49Z"),
    "__createDate" : {
        "year" : 2019,
        "month" : 8,
        "day" : 28,
        "yearMonth" : 201908,
        "yearMonthDay" : 20190829
    }
}
结果是:

// Group by __createDate.yearMonth
db.transactions.aggregate([
    { $group: {
        '_id': '$__createDate.yearMonth',
        'count': {$sum: 1},
    } },
    { $limit: 10 },
    { $sort: {'_id': -1 } }
])
// 20 169 ms

// Group by year and month
db.transactions.aggregate([
    {$group: {
            '_id': {year: '$__createDate.year', month: '$__createDate.month' },
            'count': {$sum: 1},
    }},
    { $limit: 10 },
    { $sort: {'_id': -1 } }
])
// 23 777 ms

// Group by calculating year and month from ISODate
db.transactions.aggregate([
    {$group: {
            '_id': {year: { $year: '$__createDateUtc' }, month: { $month: '$__createDateUtc' } },
            'count': {$sum: 1},
    }},
    { $limit: 10 },
    { $sort: {'_id': -1 } }
])
// 16 444 ms

// Last stupid method to just run many queries with count
var years = [2017, 2018, 2019];
var results = {}
years.forEach(year => {
    results[year] = {};
    for(var i = 1; i < 13; i++) {
        var count = db.transactions.find({'__createDate.year': year, '__createDate.month': i}).count();
        if(count > 0) results[year][i] = count;
    }
})
// 10 701 ms
//分组依据uu createDate.yearMonth
db.transactions.aggregate([
{$group:{
“\u id”:“$\u\u createDate.yearMonth”,
'计数':{$sum:1},
} },
{$limit:10},
{$sort:{''u id':-1}
])
//20 169毫秒
//按年份和月份分组
db.transactions.aggregate([
{$group:{
“\u id”:{年:'$\u createDate.year',月:'$\u createDate.month'},
'计数':{$sum:1},
}},
{$limit:10},
{$sort:{''u id':-1}
])
//23777毫秒
//按从ISODate算起的年和月分组
db.transactions.aggregate([
{$group:{
“_id”:{year:{$year:'$\uu createDateUtc'},month:{$month:'$\uu createDateUtc'}},
'计数':{$sum:1},
}},
{$limit:10},
{$sort:{''u id':-1}
])
//16444毫秒
//最后一个愚蠢的方法只是用count运行许多查询
风险值年数=[2017、2018、2019];
var结果={}
年份。forEach(年份=>{
结果[年]={};
对于(变量i=1;i<13;i++){
var count=db.transactions.find({uuuuu createDate.year':year,'.\uuuu createDate.month':i}).count();
如果(计数>0)结果[年][i]=计数;
}
})
//10701毫秒
正如您所见,最后一种只运行多个计数的方法是最快的。特别是因为与其他三种方法相比,我实际上获取了更多的数据


我觉得这很愚蠢。我知道MongoDB不是搜索引擎,但仍然是。聚合一点也不快。让我想将数据同步到弹性搜索,并尝试在ES内聚合

您是否尝试过不使用
$project
阶段?您有一个没有排序的限制。我想你只是想要过去10年的数据,但同样——没有。不确定您有多少数据,但您可以先使用$match按日期筛选,这样只考虑过去10年内的文档,因此聚合正在处理的数据集的大小会在过程中尽早减小。@barrypicker Yhey,对此表示抱歉。实际上没有10年的数据,但由于我希望每月也能分组,因此限制是作为概念证明。@JulienTASSIN删除
$project
没有任何区别。这里最昂贵的部分实际上是日期计算。。。