移动平均聚合 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 }
]