从MongoDB聚合返回每小时的单个记录,我还需要知道字段中的“模式”或最常出现的值。
到目前为止,我已经选择了两个日期之间的记录集,并且每小时返回一条记录,包括字段值的平均值。但我还需要最频繁的类别,其中类别编号字段包含1,2,3或4。
var myName = "CollectionName"
//schema for mongoose
var mySchema = new Schema({
dt: Date,
value: Number,
category: Number
});
var myDB = mongoose.createConnection('mongodb://localhost:27017/MYDB');
myDBObj = myDB.model(myName, evalSchema, myName);
以下$ group中的日期数学创建当天每小时的记录,$ avg平均价格字段....
但我不知道如何在类别字段中返回最频繁出现的1,2,3或4 ...没有$ mode聚合运算符,我收到错误"exception: unknown group operator '$mode'"
myDBObj.aggregate([
{
$match: { "dt": { $gt: new Date("October 13, 2010 12:00:00"), $lt: new Date("November 13, 2010 12:00:00") } }
},{
$group: {
"_id": {
"dt": {
"$add": [
{
"$subtract": [
{ "$subtract": ["$dt", new Date(0)] },
{
"$mod": [
{ "$subtract": ["$dt", new Date(0)] },
3600000//1000 * 60 * 60
]
}
]
},
new Date(0)
]
}
},
"price": { "$avg": "$price" },
"category" : { "$mode" : "$category"}
}
}], function (err, data) { if (err) { return next(err); } res.json(data); });
有没有办法返回字段中包含的最常见值?
我是否需要使用map-reduce功能?我如何将它们与上面的每小时聚合结合起来?谢谢你的帮助。
答案 0 :(得分:2)
嗯,你不能只是“弥补”。 $mode
运算符不是攻击运算符,您可以使用的唯一内容是those that actually exist。
因此,为了在最多发生的分组时间段内返回类别值,必须首先对每个值进行分组并返回出现次数。然后,您可以按该计数对这些结果进行排序,并返回在该时间段内记录最高计数的类别值:
// Filter dates
{ "$match": {
"dt": {
"$gt": new Date("October 13, 2010 12:00:00"),
"$lt": new Date("November 13, 2010 12:00:00")
}
}},
// Group by hour and category, with avg and count
{ "$group": {
"_id": {
"dt": {
"$add": [
{
"$subtract": [
{ "$subtract": ["$dt", new Date(0)] },
{
"$mod": [
{ "$subtract": ["$dt", new Date(0)] },
3600000//1000 * 60 * 60
]
}
]
},
new Date(0)
]
},
"category": "$category"
},
"price": { "$avg": "$price" },
"count": { "$sum": 1 }
}},
// Sort on date and count
{ "$sort": { "_id.dt": 1, "count": -1 }},
// Group on just the date, keeping the avg and the first category
{ "$group": {
"_id": "$_id.dt",
"price": { "$avg": "$price"}
"category": { "$first": "$_id.category" }
}}
在日期和类别上都$group
,并通过$sum
保留类别计数。然后你$sort
所以最大的“计数”在每个分组日期的顶部。当您应用刚刚应用于日期本身的另一个$group
时,最后使用$first
,以便返回每个日期具有最大计数的类别。
不要被像$max
这样的运营商诱惑,因为它们在这里不起作用。关键的区别在于对每个类别值产生的“记录/文档”的“绑定”关联。因此,它不是您想要的最大“计数”或最大“类别”值,而是“产生”最大计数的类别值。因此,此处需要$sort
。
最后你应该“破坏”一些习惯:
除非您确实知道自己在做什么,否则请勿使用非UTC格式的日期实例数据作为输入。日期将始终转换为UTC,因此至少在测试列表中,您应该习惯于指定日期值。
从另一个角度来看,它可能看起来更清晰,但像1000 * 60 * 60
之类的东西比3600000
更能解释它所做的事情。相同的值,但是一种形式表明它的时间单位一目了然。
当只有一个值时,复合_id
也会混淆问题。因此,如果这是唯一存在的值,则访问_id.dt
几乎没有意义。什么时候只有_id
内的单个属性,那就没关系了。但是单个值应该仅仅分配给_id
。没有什么可以获得,单身就很清楚了。