接受的答案对我有所帮助,但是我花了一些时间才理解它的工作原理,因此我想解释一下我的方法以帮助其他人。特别是在您的情况下,我认为我的答案会有所帮助。
这适用于较小的数据集
首先按天分组数据,然后将每天的所有日期附加到一个数组中:
{
"$sort": {
"Date": -1
}
},
{
"$group": {
"_id": {
"Day": "$Date",
"Temperature": "$Temperature"
},
"Previous Values": {
"$push": {
"Date": "$Date",
"Temperature": "$Temperature"
}
}
}
这将为您留下一个看起来像这样的记录(它将被正确排序):
{"_id.Day": "2017-02-01",
"Temperature": 40,
"Previous Values": [
{"Day": "2017-03-01", "Temperature": 20},
{"Day": "2017-02-11", "Temperature": 22},
{"Day": "2017-01-18", "Temperature": 03},
...
]},
现在每天都添加了所有日期,我们需要从“Previous Values”数组中删除比this _id.Day字段更近的项目,因为移动平均是向后看的:
{
"$project": {
"_id": 0,
"Date": "$_id.Date",
"Temperature": "$_id.Temperature",
"Previous Values": 1
}
},
{
"$project": {
"_id": 0,
"Date": 1,
"Temperature": 1,
"Previous Values": {
"$filter": {
"input": "$Previous Values",
"as": "pv",
"cond": {
"$lte": ["$$pv.Date", "$Date"]
}
}
}
}
},
先前值数组中的每个项目仅包含小于或等于每个记录日期的日期:
{"Day": "2017-02-01",
"Temperature": 40,
"Previous Values": [
{"Day": "2017-01-31", "Temperature": 33},
{"Day": "2017-01-30", "Temperature": 36},
{"Day": "2017-01-29", "Temperature": 33},
{"Day": "2017-01-28", "Temperature": 32},
...
]}
现在我们可以选择平均窗口大小,因为数据是按天计算的,对于一周,我们将取数组的前7个记录;对于每月,取30个记录;或者对于每3个月,取90天的记录:
{
"$project": {
"_id": 0,
"Date": 1,
"Temperature": 1,
"Previous Values": {
"$slice": ["$Previous Values", 0, 90]
}
}
},
为了对先前的温度进行平均,我们需要展开“Previous Values”数组,然后按日期字段进行分组。展开操作会执行以下步骤:
{"Day": "2017-02-01",
"Temperature": 40,
"Previous Values": {
"Day": "2017-01-31",
"Temperature": 33}
},
{"Day": "2017-02-01",
"Temperature": 40,
"Previous Values": {
"Day": "2017-01-30",
"Temperature": 36}
},
{"Day": "2017-02-01",
"Temperature": 40,
"Previous Values": {
"Day": "2017-01-29",
"Temperature": 33}
},
...
注意看到 Day 字段是相同的,但现在我们有了 Previous Values 数组中每个之前日期的文档。现在我们可以按天分组,然后对 Previous Values.Temperature 取平均值以获得移动平均值:
{"$group": {
"_id": {
"Day": "$Date",
"Temperature": "$Temperature"
},
"3 Month Moving Average": {
"$avg": "$Previous Values.Temperature"
}
}
}
没错!我知道将每个记录与每个记录连接起来并不理想,但对于较小的数据集来说,这样做效果还不错。