【问题标题】:Calculating multiple averages using MongoDB Aggregation使用 MongoDB 聚合计算多个平均值
【发布时间】:2014-08-12 23:06:42
【问题描述】:

我的任务是为 MongoDB 中相当大的一组文档生成日、周、月和年的平均值。

所有作业都有一个created 字段,我需要基于outputs 数组的平均值...

这是文档的样子:

{
  __v: 0,
  _id: ObjectId("535837911393fd0200d8e1eb"),
  created: ISODate("2014-04-23T21:58:41.446Z"),
  output: [
    {
      ref: {
        img: false
      },
      type: "image/png",
      methods: [
        {
          options: {
            height: 200,
            width: 200
          },
          method: "resize"
        }
      ]
    },
    {
      ref: {
        img: false
      },
      type: "image/png",
      methods: [
        {
          options: {
            height: 400,
            width: 400
          },
          method: "resize"
        }
      ]
    }
  ]
}

这是我当前脚本的样子:

JobModel.aggregate([
    {
        $unwind: '$output'
    },
    {
        $group: {
            _id: { $dayOfYear: '$created' },
            day: { $sum: 1 }
        }
},
{
    $group: {
        _id: null,
        avgDay: { $avg: '$day' }
    }
},
{
        $project: {
            _id: 0,
            average: {
                day: '$avgDay'
            }
        }
    }
],
function(err, data) {

    if (err) {
        console.log(err);
        return;
    }

    res.send(data);
    next();

});

我似乎无法找出正确的顺序。有什么建议吗?

【问题讨论】:

    标签: javascript node.js mongodb mongoose aggregation-framework


    【解决方案1】:

    真的不知道你在这里追求什么。您说您想要“多个”平均值,但这提出了“多个”基于什么基础的问题?一天中的平均“输出”条目将不同于每月的平均输出条目,甚至不同于每月的每日平均输出条目。所以规模随着每次选择而变化,并不是真正的“每日”、“每月”和“每年”的单个查询

    我认为您确实是“离散”总计,最好通过首先找到输出条目的“大小”然后应用每个比例的平均值来接近:

    JobModel.aggregate(
        [
            { "$unwind": "$output" },
    
            // Count the array entries on the record
            { "$group": {
                "_id": "$_id",
                "created": { "$first": "$created" },
                "count": { "$sum": 1 }
            }},
    
            // Now get the average per day
            { "$group": {
                "_id": { "$dayOfYear": "$created" },
                "avg": { "$avg": "$count" }
            }}
        ],
        function(err,result) {
    
        }
    );
    

    或者实际上使用 MongoDB 2.6 及更高版本,您可以在数组上使用 $size 运算符:

    JobModel.aggregate(
        [
            // Now get the average per day
            { "$group": {
                "_id": { "$dayOfYear": "$created" },
                "avg": { "$avg": { "$size": "$output" } }
            }}
        ],
        function(err,result) {
    
        }
    );
    

    因此,合乎逻辑的事情是在您所需的$match 范围内运行每一个,而不是您的“日”、“月”或“年”的聚合键

    您可以通过将结果组合到数组中来执行诸如将每天的每日平均值与每月的每日平均值组合起来,然后将每年的每日平均值组合成数组,否则您只会扔掉物品,如果您“只是" 想要当年的日平均值,但要得到完整的结果:

    JobModel.aggregate(
        [
            // Now get the average per day
            { "$group": {
                "_id": { 
                    "year": { "$year": "$created" },
                    "month": { "$month": "$created" },
                    "day": { "$dayOfYear": "$created" }
                },
                "dayAvg": { "$avg": { "$size": "$output" } }
            }},
    
            // Group for month
            { "$group": {
                "_id": {
                    "year": "$_id.year",
                    "month": "$_id.month"
                },
                "days": { 
                    "$push": {
                        "day": "$_id.day",
                        "avg": "$dayAvg"
                    }
                },
                "monthAvg": { "$avg": "$dayAvg" }
            }},
    
            // Group for the year
            { "$group": {
                "_id": "$_id.year",
                "daily": { "$avg": "$monthAvg" },
                "months": {
                    "$push": {
                        "month": "$_id.month",
                        "daily": "$monthAvg",
                        "days": "$days"
                    }
               }
            }}
        ],
        function(err,result) {
    
        }
    );
    

    但是您想应用它,但您的示例中缺少的主要内容是找到每个文档的原始“输出”数组的“大小”或“计数”,从中获得平均值。

    【讨论】:

    • 非常有帮助。我正在尝试获取用户生命周期的平均值。所以这将是第一个提交的作业,到最后一个提交的作业。你有没有机会提供一个例子?谢谢!
    • @NickParsons 从您的问题的上下文中不太清楚。什么是“用户”?我在你的方法中看不到任何指向“用户”的东西,本质上。我看起来这个数据在某种程度上是“用户”的“孩子”。如果没有此数据的“用户”键,您唯一的选择是通过$in 选择此集合的_id 值。通常,如果您有其他问题,那么您最好提出一个单独的问题。它不会混淆给出的答案,并且可以让您清楚地说明您的意图。
    • @NielLunn 抱歉,让用户感到困惑。我想要做的是生成日期范围之间的平均值。例如,我想使用创建时间获取过去 30 天内的所有工作。然后,我想获得每天、每小时、每分钟和每秒钟的平均工作。我需要考虑没有文件的日子。
    • @NickParsons 正如我已经提到的那样,我认为可以公平地说您的问题已经得到解答。您已经获得了一些关于如何解决此问题的指示,并且在您使用的方法中也得到了纠正。我还说过,除非在给出的示例上下文中,否则在单个查询中通常不可能有各种“时间范围”。你正在改变你的问题的上下文,虽然作为一个问题是有效的,但它实际上是一个不同的问题。您需要照此发布,以免将来引用此问题和答案的人感到困惑。
    猜你喜欢
    • 2012-10-11
    • 1970-01-01
    • 2023-04-05
    • 1970-01-01
    • 1970-01-01
    • 2016-02-15
    • 2018-11-16
    • 2020-06-26
    • 1970-01-01
    相关资源
    最近更新 更多