移动平均聚合 MongoDB
Moving average aggregation MongoDB
我正在寻找一种简单的方法来计算给定日期的 90 天移动平均线。我有一个名为 Response 的文档,它具有给定的结构:
{
_id: ObjectId("60e4cf6e783e125bd80f1cf5"),
createdAt: 2021-07-06T21:47:26.282+00:00,
value: 8
}
我知道如何计算给定日期的 90 天移动平均线,例如 2021-08-10,但我想要实现的是这种类型的数组:
[
{date: 2021-08-10, average: 6.7},
{date: 2021-08-09, average: 6.8},
{date: 2021-08-08, average: 6.5},
...
]
我试图计算循环内一组日期的移动平均值,但考虑到我需要计算多达 365 个不同日期的移动平均值,性能绝对糟糕。
关于如何解决这个问题有什么想法吗?非常感谢您的帮助。
如果您还没有 运行 Monog 5.0,那么这将是一个起点:
db.collection.aggregate([
{ $group: { _id: null, data: { $push: "$$ROOT" } } },
{
$set: {
data: {
$map: {
input: { $range: [0, { $size: "$data" }] },
as: "idx",
in: {
createdAt: { $arrayElemAt: ["$data.createdAt", "$$idx"] },
window: {
$filter: {
input: "$data",
cond: {
$and: [
{ $gte: ["$$this.createdAt", { $arrayElemAt: ["$data.createdAt", "$$idx"] }] },
{ $lt: ["$$this.createdAt", { $add: [{ $arrayElemAt: ["$data.createdAt", "$$idx"] }, 1000 * 60 * 60 * 24 * 90] }] }
]
}
}
},
}
}
}
}
},
{
$set: {
data: {
$map: {
input: "$data",
in: {
createdAt: "$$this.createdAt",
window: "$$this.window.value",
average: {$avg: "$$this.window.value"}
}
}
}
}
}
])
Wernfried 的回答非常接近我需要的解决方案。这是我的最终方法:
db.collection.aggregate([
{
$group: {
_id: null,
data: {
$push: "$$ROOT",
},
},
},
{
$set: {
data: {
$map: {
input: {
$range: [0, period],
},
as: "idx",
in: {
date: {
$subtract: [
moment().toDate(),
{ $multiply: [1000 * 60 * 60 * 24, "$$idx"] },
],
},
window: {
$filter: {
input: "$data",
cond: {
$and: [
{
$lte: [
"$$this.createdAt",
{
$subtract: [
moment().toDate(),
{ $multiply: [1000 * 60 * 60 * 24, "$$idx"] },
],
},
],
},
{
$gte: [
"$$this.createdAt",
{
$subtract: ["$date", 1000 * 60 * 60 * 24 * 90],
},
],
},
],
},
},
},
},
},
},
},
},
{
$set: {
data: {
$map: {
input: "$data",
in: {
date: "$$this.date",
score: {
$avg: "$$this.window.value",
},
},
},
},
},
},
])
其中周期是我需要移动平均线的天数。这将对 period = 7 产生以下响应:
[
{ date: 2021-08-11T21:49:49.097Z, score: 6.513605442176871 },
{ date: 2021-08-10T21:49:49.097Z, score: 6.513605442176871 },
{ date: 2021-08-09T21:49:49.097Z, score: 6.556818181818182 },
{ date: 2021-08-08T21:49:49.097Z, score: 6.556818181818182 },
{ date: 2021-08-07T21:49:49.097Z, score: 6.556818181818182 },
{ date: 2021-08-06T21:49:49.097Z, score: 6.556818181818182 },
{ date: 2021-08-05T21:49:49.097Z, score: 6.497863247863248 }
]
我正在寻找一种简单的方法来计算给定日期的 90 天移动平均线。我有一个名为 Response 的文档,它具有给定的结构:
{
_id: ObjectId("60e4cf6e783e125bd80f1cf5"),
createdAt: 2021-07-06T21:47:26.282+00:00,
value: 8
}
我知道如何计算给定日期的 90 天移动平均线,例如 2021-08-10,但我想要实现的是这种类型的数组:
[
{date: 2021-08-10, average: 6.7},
{date: 2021-08-09, average: 6.8},
{date: 2021-08-08, average: 6.5},
...
]
我试图计算循环内一组日期的移动平均值,但考虑到我需要计算多达 365 个不同日期的移动平均值,性能绝对糟糕。
关于如何解决这个问题有什么想法吗?非常感谢您的帮助。
如果您还没有 运行 Monog 5.0,那么这将是一个起点:
db.collection.aggregate([
{ $group: { _id: null, data: { $push: "$$ROOT" } } },
{
$set: {
data: {
$map: {
input: { $range: [0, { $size: "$data" }] },
as: "idx",
in: {
createdAt: { $arrayElemAt: ["$data.createdAt", "$$idx"] },
window: {
$filter: {
input: "$data",
cond: {
$and: [
{ $gte: ["$$this.createdAt", { $arrayElemAt: ["$data.createdAt", "$$idx"] }] },
{ $lt: ["$$this.createdAt", { $add: [{ $arrayElemAt: ["$data.createdAt", "$$idx"] }, 1000 * 60 * 60 * 24 * 90] }] }
]
}
}
},
}
}
}
}
},
{
$set: {
data: {
$map: {
input: "$data",
in: {
createdAt: "$$this.createdAt",
window: "$$this.window.value",
average: {$avg: "$$this.window.value"}
}
}
}
}
}
])
Wernfried 的回答非常接近我需要的解决方案。这是我的最终方法:
db.collection.aggregate([
{
$group: {
_id: null,
data: {
$push: "$$ROOT",
},
},
},
{
$set: {
data: {
$map: {
input: {
$range: [0, period],
},
as: "idx",
in: {
date: {
$subtract: [
moment().toDate(),
{ $multiply: [1000 * 60 * 60 * 24, "$$idx"] },
],
},
window: {
$filter: {
input: "$data",
cond: {
$and: [
{
$lte: [
"$$this.createdAt",
{
$subtract: [
moment().toDate(),
{ $multiply: [1000 * 60 * 60 * 24, "$$idx"] },
],
},
],
},
{
$gte: [
"$$this.createdAt",
{
$subtract: ["$date", 1000 * 60 * 60 * 24 * 90],
},
],
},
],
},
},
},
},
},
},
},
},
{
$set: {
data: {
$map: {
input: "$data",
in: {
date: "$$this.date",
score: {
$avg: "$$this.window.value",
},
},
},
},
},
},
])
其中周期是我需要移动平均线的天数。这将对 period = 7 产生以下响应:
[
{ date: 2021-08-11T21:49:49.097Z, score: 6.513605442176871 },
{ date: 2021-08-10T21:49:49.097Z, score: 6.513605442176871 },
{ date: 2021-08-09T21:49:49.097Z, score: 6.556818181818182 },
{ date: 2021-08-08T21:49:49.097Z, score: 6.556818181818182 },
{ date: 2021-08-07T21:49:49.097Z, score: 6.556818181818182 },
{ date: 2021-08-06T21:49:49.097Z, score: 6.556818181818182 },
{ date: 2021-08-05T21:49:49.097Z, score: 6.497863247863248 }
]