我有以下MongoDB聚合查询,它查找指定月份内的所有记录,$按天分组记录,然后返回每天的平均价格。我还希望返回整个月的平均价格。我可以通过使用多个$组来实现这一点,如果是这样,怎么做?
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
});
答案 0 :(得分:1)
简短的回答是“只是将您的日期范围扩展到包含一个月内的所有日期有什么问题?”,因此您只需更改即可获得结果。
你可以“嵌套”分组阶段吗?是的,您可以向管道添加其他阶段,这就是管道的用途。因此,如果您首先想要每天“平均”然后在一个月的所有日子里取平均值,那么您可以这样形成:
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" }
}}
])
即使这可能是相当多余的,因为可以说这可以通过一个单一的群体陈述来完成。
但是这个架构有更长的评论。除了获得平均值或模式意图包含的内容之外,您实际上并没有说明您正在做的事情的大部分目的。所以我想描述一些可能有点不同的东西。
假设您有一个包含“产品”的集合,“键入”“当前价格”和“时间戳”作为“价格”“更改”的日期。我们称之为“PriceChange”。因此,每次发生此事件时,都会创建一个新文档。
{
"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" }
}}
])
因此,您可以使用Date Aggregation Operators中的构建来实现各种结果。这些甚至可以帮助收集这些信息,以便写入新的“预聚合”集合,用于更快的分析。
我想有一种方法可以使用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 };
}
}
)
这将返回类似的内容:
{
"results" : [
{
"_id" : 1,
"value" : {
"dayAvg" : 105,
"monthAvg" : 105
}
},
{
"_id" : 2,
"value" : {
"dayAvg" : 110,
"monthAvg" : 107.5
}
}
],
}
但如果您希望看到日期和月份的离散值,那么如果不运行单独的查询则无法实现。