使用MongoDB Aggregation计算多个平均值

时间:2014-06-23 00:13:07

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

我的任务是为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();

});

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

1 个答案:

答案 0 :(得分:1)

真的不确定你在这之后是什么。你说你想要"多个"平均值,但这提出了" muliple"在什么基础上?平均"输出"单个日期的条目与每月的平均输出条目或甚至每月的每日平均值不同。因此,每个选择的比例都会随着每个选择的变化而变化,并且实际上并不是每日","每月"和"每年"

我觉得你真的是"离散"通过首先找到"尺寸"最好接近的总数。输出条目然后应用每个比例的平均值:

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范围内运行其中的每一个,其他的聚合键是" day"," month"或"年"

你可以做一些事情,例如将每日平均值与每月平均值相结合,然后将结果组合成数组,然后将结果放入数组中,否则你只是扔掉物品,如果你&#可以交替完成34;只是"想要一年中的每日平均值,但需要完整的结果:

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) {

    }
);

但是你想要应用它,但你的例子中缺少的主要内容是找到" size"或"计数"原始"输出"每个文档的数组,从中获得平均值。