Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/463.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript MongoDB聚合框架-如何执行多个$group查询_Javascript_Node.js_Mongodb_Mongoose_Aggregation Framework - Fatal编程技术网

Javascript MongoDB聚合框架-如何执行多个$group查询

Javascript MongoDB聚合框架-如何执行多个$group查询,javascript,node.js,mongodb,mongoose,aggregation-framework,Javascript,Node.js,Mongodb,Mongoose,Aggregation Framework,我有以下MongoDB聚合查询,它查找指定月份内的所有记录,$按天对记录进行分组,然后返回每天的平均价格。我还想返回整个月的平均价格。我可以通过使用多个$group来实现这一点吗?如果可以,如何实现 PriceHourly.aggregate([ { $match: { date: { $gt: start, $lt: end } } }, { $group: { _id:

我有以下MongoDB聚合查询,它查找指定月份内的所有记录,$按天对记录进行分组,然后返回每天的平均价格。我还想返回整个月的平均价格。我可以通过使用多个$group来实现这一点吗?如果可以,如何实现

        PriceHourly.aggregate([
                { $match: { date: { $gt: start, $lt: end } } },
                { $group: { 
                    _id: "$day", 
                    price: { $avg: '$price' },
                    system_demand: { $avg: '$system_demand'}
                }}
        ], function(err, results){

                results.forEach(function(r) {
                    r.price          = Helpers.round_price(r.price);
                    r.system_demand  = Helpers.round_price(r.system_demand);
                });
                console.log("Results Length: "+results.length, results);
                res.jsonp(results);
        }); // PriceHourly();  
这是我的模型:

// Model
var PriceHourlySchema = new Schema({
    created: {
        type: Date,
        default: Date.now
    },
    day: {
        type: String,
        required: true,
        trim: true
    },
    hour: {
        type: String,
        required: true,
        trim: true
    },
    price: {
        type: Number,
        required: true
    },
    date: {
        type: Date,
        required: true
    }
}, 
{ 
    autoIndex: true 
});
简单的回答是“把你的日期范围扩大到包括一个月内的所有日子有什么不对?”因此,为了得到结果,你只需要改变这些

你能“嵌套”分组阶段吗?是的,您可以向管道添加其他阶段,这就是管道的用途。因此,如果您首先想“平均”每天,然后计算一个月内所有天数的平均值,您可以这样形成:

PriceHourly.aggregate([
   { "$match": { 
       "date": { 
           "$gte": new Date("2014-03-01"), "$lt": new Date("2014-04-01")
       }  
   }},
   { "$group": { 
       "_id": "$day", 
       "price": { "$avg": "$price" },
       "system_demand": { "$avg": "$system_demand" }
   }},
   { "$group": { 
       "_id": null, 
       "price": { "$avg": "$price" },
       "system_demand": { "$avg": "$system_demand" }
   }}
])
{
    "results" : [
        {
            "_id" : 1,
            "value" : {
                "dayAvg" : 105,
                "monthAvg" : 105
            }
        },
        {
            "_id" : 2,
            "value" : {
                "dayAvg" : 110,
                "monthAvg" : 107.5
           }
        }
    ],
}
即使这可能是合理的冗余,因为这可以用一个单独的集团声明来完成

但对这一模式还有更长的评论。实际上,除了获得平均值或模式要包含的内容外,您并没有说明所做工作的大部分目的。所以我想描述一些可能有点不同的东西

假设您有一个集合,其中包括“产品”、“键入”当前价格和“时间戳”,作为“价格”被“更改”的日期。让我们把这个集合称为“价格变化”。因此,每次发生此事件时,都会创建一个新文档

{
    "product": "ABC",
    "type": 2,
    "price": 110,
    "timestamp": ISODate("2014-04-01T00:08:38.360Z")
}
这可能在一小时、一天或任何情况下改变很多次

因此,如果您对当月每种产品的“平均”价格感兴趣,您可以这样做:

PriceChange.aggregate([
    { "$match": {
        "timestamp": { 
            "$gte": new Date("2014-03-01"), "$lt": new Date("2014-04-01")
        }
    }},
    { "$group": {
        "_id": "$product",
        "price_avg": { "$avg": "$price" }
    }}
])
此外,无需任何其他字段,您可以获得每月每天的每种产品的平均价格:

PriceChange.aggregate([
    { "$match": {
        "timestamp": { 
            "$gte": new Date("2014-03-01"), "$lt": new Date("2014-04-01")
        }
    }},
    { "$group": {
        "_id": {
            "day": { "$dayOfMonth": "$timestamp" },
            "product": "$product"
        },
        "price_avg": { "$avg": "$price" }
    }}
])
或者,您甚至可以获得一整年中每个月的上一次价格:

PriceChange.aggregate([
    { "$match": {
        "timestamp": { 
            "$gte": new Date("2013-01-01"), "$lt": new Date("2014-01-01")
        }
    }},
    { "$group": {
        "_id": {
            "date": {
                "year": { "$year" : "$timestamp" },
                "month": { "$month": "$timestamp" }
            },
            "product": "$product"
        },
        "price_last": { "$last": "$price" }
    }}
])
因此,您可以使用内置来实现各种结果。这些甚至可以帮助收集这些信息,以便写入新的“预聚合”集合,以用于更快的分析

我想有一种方法可以使用mapReduce将“运行”平均值与所有价格相结合。再次从我的样本来看:

PriceHourly.mapReduce(
    function () {
        emit( this.timestamp.getDate(), this.price )
    },
    function (key, values) {
        var sum = 0;
        values.forEach(function(value) {
            sum += value;
        });
        return ( sum / values.length );
    },
    { 
        "query": {
            "timestamp": {
                "$gte": new Date("2014-03-01"), "$lt": new Date("2014-04-01")
            }
        },
        "out": { "inline": 1 },
        "scope": { "running": 0, "counter": 0 },
        "finalize": function(key,value) {
            running += value;
            counter++;
            return { "dayAvg": value, "monthAvg": running / counter };
        }
    }
)
这将返回类似这样的结果:

PriceHourly.aggregate([
   { "$match": { 
       "date": { 
           "$gte": new Date("2014-03-01"), "$lt": new Date("2014-04-01")
       }  
   }},
   { "$group": { 
       "_id": "$day", 
       "price": { "$avg": "$price" },
       "system_demand": { "$avg": "$system_demand" }
   }},
   { "$group": { 
       "_id": null, 
       "price": { "$avg": "$price" },
       "system_demand": { "$avg": "$system_demand" }
   }}
])
{
    "results" : [
        {
            "_id" : 1,
            "value" : {
                "dayAvg" : 105,
                "monthAvg" : 105
            }
        },
        {
            "_id" : 2,
            "value" : {
                "dayAvg" : 110,
                "monthAvg" : 107.5
           }
        }
    ],
}

但是,如果您希望同时看到日和月的离散值,那么如果不运行单独的查询,这是不可能的。

Neil,感谢您包含所有这些信息,这非常有帮助。然而,我无法让这两种方法同时返回日平均值和月平均值。第一种方法只返回月平均值,第二个$group似乎覆盖了日平均值。如果我删除第二个$group,每日平均值将按预期返回。第二种方法会导致一个错误声明:{[MongoError:exception:invalid operator'$avg']name:'MongoError',errmsg:'exception:invalid operator\'$avg\'',代码:15999,ok:0}@ac360抱歉,您想要实现什么?您希望在同一结果集中同时显示日平均值和月平均值吗?我甚至不确定那应该是什么样子,从你的问题中当然不清楚。也不确定您所指的是哪个列表上的错误。可能存在键入错误(我发现了一个),因为这些只是作为示例键入的。@ac360确实不确定您想在这里实现什么。我添加了一个具有运行平均值的样本。结果仍然有问题吗?你不能按照你描述的方式来组合结果,将月平均数与日平均数结合起来也没有多大意义,除非你指的是每个累积日的“运行平均数”。否则,两组数据最适合两个查询。在这两种情况下,您的问题都可以从显示您似乎期望的结果数据中获益。