在我的聚合中,流中的每个文档都会有一个日期。
我需要在日期范围内总结一些值..
即
{
value: 3,
date: [SoME TIME STAMP]
},
{
value: 4,
date: [SoME TIME STAMP]
},
{
value: 1,
date: [SoME TIME STAMP]
},
{
value: -6,
date: [SoME TIME STAMP]
}
我希望能够根据日期范围对这些文档进行分组。 IE:1-7天前,8-15天前。和15-30天前。
db.Collection.aggregate([
{$match: {some matching}},
{$group: {What should i do here??}}
])
我当然可以做3种不同的聚合,在日期上有3种不同的$ match。
是否可以执行所有$ group并在一次运行中对“value”字段求和?
答案 0 :(得分:24)
您需要根据当前日期在范围之间的位置有条件地确定分组键。这基本上是通过$cond
使用嵌套条件和$lt
的逻辑变体实现的:
// work out dates somehow
var today = new Date(),
oneDay = ( 1000 * 60 * 60 * 24 ),
thirtyDays = new Date( today.valueOf() - ( 30 * oneDay ) ),
fifteenDays = new Date( today.valueOf() - ( 15 * oneDay ) ),
sevenDays = new Date( today.valueOf() - ( 7 * oneDay ) );
db.collection.aggregate([
{ "$match": {
"date": { "$gte": thirtyDays }
}},
{ "$group": {
"_id": {
"$cond": [
{ "$lt": [ "$date", fifteenDays ] },
"16-30",
{ "$cond": [
{ "$lt": [ "$date", sevenDays ] },
"08-15",
"01-07"
]}
]
},
"count": { "$sum": 1 },
"totalValue": { "$sum": "$value" }
}}
])
由于$cond
是三元运算符,因此计算第一个条件以查看条件是否为真,如果为true则返回第二个参数,否则返回第三个条件为false。因此,通过在虚假案例中嵌套另一个$cond
,您可以对日期所在的位置进行逻辑测试,或者“少于15天的日期”,这意味着它在最旧的范围内,或者“少于7天”,这意味着中间范围,当然还是最新的范围。
我只是在这里使用0
为小于10的数字添加前缀,因此如果需要,它会为您提供一些排序,因为$group
中“键”的输出本身并不存在排序。
但这就是你在单个查询中执行此操作的方法。您只需根据日期的下降位置计算出分组键的内容,并为每个键累积。
答案 1 :(得分:4)
第一步是创建代表你的范围的日期对象。让我们假设你想在8-15天前运行dange的聚合操作,这意味着你需要两个日期对象,比如说开始和结束。 start将保留一天前的日期,结束将保留8天前的日期。创建这些日期对象很容易,因为从n
是前几天的日期减去n
,将它们设置为之前的天数:
var start = new Date();
start.setDate(start.getDate() - 8);
var end = new Date();
end.setDate(end.getDate() - 15);
或使用.getTime()
方法从时间戳毫秒减去返回标准JavaScript时间戳(自Jan 1/1970
以来的毫秒数),您可以使用常规数学运算,并直接反馈到Date对象:
var today = new Date();
var start = new Date(today.getTime() - 8*24*60*60*1000);
var end = new Date(today.getTime() - 15*24*60*60*1000);
现在您已拥有日期对象,然后可以将它们用作 $match
条件,并使用 $lte
和 $gte
比较运营商:
var pipeline = [
{
"$match": {
"date": { "$lte": start, "$gte": end }
}
}
]
在此阶段运行聚合将为您提供日期在8-15天之前的所有文档,
db.aggregate(pipeline);
相当于 find()
查询:
db.collection.find({
"date": { "$lte": start, "$gte": end }
});
现在,在下一个管道阶段,您需要创建一个指定组_id
为null的聚合操作,使用 {计算集合中所有文档的总值和计数。 {3}} 累加器运算符:
var pipeline = [
{
"$match": {
"date": { "$lte": start, "$gte": end }
}
},
{
"$group": {
"_id": null,
"totalValues": { "$sum": "$value" },
"count": { "$sum": 1 }
}
}
]
db.collection.aggregate(pipeline);
您甚至可以进一步创建一个泛型函数,该函数返回上述聚合操作的实际总数,该操作包含两个参数:日期范围的起始值和结束:
var getTotalValues = function(start, end){
var today = new Date();
var startDate = new Date(today.getTime() - start*24*60*60*1000);
var endDate = new Date(today.getTime() - end*24*60*60*1000);
var pipeline = [
{
"$match": {
"timestamp": { "$lte": startDate, "$gte": endDate }
}
},
{
"$group": {
"_id": null,
"totalValues": { "$sum": "$value" },
"count": { "$sum": 1 }
}
}
],
resultArray = db.collection.aggregate(pipeline).toArray();
return resultArray[0].totalValues;
}
var total = getTotalValues(1, 8);
printjson(total); // prints the total