MongoDB通过created_at月聚合

siv3szwd  于 2023-04-29  发布在  Go
关注(0)|答案(1)|浏览(406)

我有一个充满实体的集合,我正在使用MongoDB聚合来卸载我的后端进程所做的一些工作。我设法转换了很多端点,我错过了一个为我的时间轴生成数据的端点。
我在聚合中使用以下代码片段来检索对象所需的格式:

{ $dateToString: { format: '%Y-%m', date: '$created_at' } }

我将能够从聚合中获得以下结果:

"timeline": {
   "by_month": {
        "2023-04": 5000,
        "2023-03": 7000,
        "2023-02": 10000,
        "2023-01": 0,
        "2022-12": 0,
        "2022-11": 1000,
        "2022-10": 2000,
        "2022-09": 3000,
        "2022-08": 1000,
        "2022-07": 500,
        "2022-06": 200,
        "2022-05": 700
    },
}

基于我在聚合中指定的一些条件。
字段by_month当然需要添加,可能在聚合中添加**$addFields**指令。
对我来说最困难的部分是:

  • 从$dateToString结果创建MongoDB对象键
  • 创建一个by_month关键字,即使是没有条目的月份

是否可以直接从聚合中实现这一点?现在我用光标在实体上循环,但性能真的很差。
例如,给定以下示例文档:

[
  {
    "key": 1,
    "created_at": "2023-04-02T11:53:19.779+00:00"
  },
  {
    "key": 2,
    "created_at": "2023-03-02T11:53:19.779+00:00"
  },
  {
    "key": 3,
    "created_at": "2023-01-02T11:53:19.779+00:00"
  }
]

我希望得到以下输出:

"timeline": {
   "by_month": {
        "2023-04": 1,
        "2023-03": 1,
        "2023-02": 0,
        "2023-01": 1,
        "2022-12": 0,
        "2022-11": 0,
        "2022-10": 0,
        "2022-09": 0,
        "2022-08": 0,
        "2022-07": 0,
        "2022-06": 0,
        "2022-05": 0
    },
}

答案是惊人的,然而,如果我们有类似以下实体的东西:

[
  {
    "key": 1,
    "created_at": ISODate("2023-04-02T13:53:19.779Z"),
    "updated_at": ISODate("2023-04-02T13:53:19.779Z")
  },
  {
    "key": 2,
    "created_at": ISODate("2023-03-02T12:53:19.779Z"),
    "updated_at": ISODate("2023-04-02T13:53:19.779Z")
  },
  {
    "key": 3,
    "created_at": ISODate("2023-01-02T12:53:19.779Z"),
    "updated_at": ISODate("2023-04-02T13:53:19.779Z")
  },
  {
    "key": 4,
    "created_at": ISODate("2023-04-02T12:53:19.779Z"),
    "updated_at": ISODate("2023-04-02T13:53:19.779Z")
  }
]

是否可以在同一个查询中按不同的键进行分组,并获得以下结果?

"timeline": {
   "created_by_month": {
        "2023-04": 2,
        "2023-03": 1,
        "2023-02": 0,
        "2023-01": 1,
        "2022-12": 0,
        "2022-11": 0,
        "2022-10": 0,
        "2022-09": 0,
        "2022-08": 0,
        "2022-07": 0,
        "2022-06": 0,
        "2022-05": 0
    },
  "updated_by_month": {
        "2023-04": 4,
        "2023-03": 0,
        "2023-02": 0,
        "2023-01": 0,
        "2022-12": 0,
        "2022-11": 0,
        "2022-10": 0,
        "2022-09": 0,
        "2022-08": 0,
        "2022-07": 0,
        "2022-06": 0,
        "2022-05": 0
    },
}
gjmwrych

gjmwrych1#

你可以试试这个:

db.collection.aggregate([
   {
      $group: {
         _id: {
            $dateTrunc: {
               date: "$created_at",
               unit: "month"
            }
         },
         count: { $count: {} }
      }
   },
   {
      $densify: {
         field: "_id",
         range: {
            step: 1,
            unit: "month",
            bounds: [ISODate("2022-05-01"), ISODate("2023-04-01")]
         }
      }
   },
   { $fill: { output: { count: { value: 0 } } } },
   {
      $project: {
         by_month: {
            k: { $dateToString: { format: '%Y-%m', date: '$_id' } },
            v: "$count"
         }
      }
   },
   { $group: { _id: null, by_month: { $push: "$by_month" } } },
   { $project: { _id: 0, timeline: { by_month: { $arrayToObject: "$by_month" } } } }
])

Mongo Playground

更新

由于字段数量有限,您可以使用$facet对多个字段进行分组:

db.collection.aggregate([
   {
      $facet: {
         created_at: [
            {
               $group: {
                  _id: {
                     $dateTrunc: {
                        date: "$created_at",
                        unit: "month"
                     }
                  },
                  count: { $count: {} }
               }
            },
            {
               $densify: {
                  field: "_id",
                  range: {
                     step: 1,
                     unit: "month",
                     bounds: [ISODate("2022-05-01"), ISODate("2023-04-01")]
                  }
               }
            },
            { $fill: { output: { count: { value: 0 } } } },
            {
               $project: {
                  _id: 0,
                  by_month: {
                     k: { $dateToString: { format: '%Y-%m', date: '$_id' } },
                     v: "$count"
                  }
               }
            }
         ],
         updated_at: [
            {
               $group: {
                  _id: {
                     $dateTrunc: {
                        date: "$updated_at",
                        unit: "month"
                     }
                  },
                  count: { $count: {} }
               }
            },
            {
               $densify: {
                  field: "_id",
                  range: {
                     step: 1,
                     unit: "month",
                     bounds: [ISODate("2022-05-01"), ISODate("2023-04-01")]
                  }
               }
            },
            { $fill: { output: { count: { value: 0 } } } },
            {
               $project: {
                  _id: 0,
                  by_month: {
                     k: { $dateToString: { format: '%Y-%m', date: '$_id' } },
                     v: "$count"
                  }
               }
            }
         ],
      }
   },
   {
      $group: {
         _id: null,
         created_at: { $first: "$created_at" },
         updated_at: { $first: "$updated_at" }
      }
   },
   {
      $project: {
         _id: 0,
         timeline: {
            created_at: { $arrayToObject: "$created_at.by_month" },
            updated_at: { $arrayToObject: "$updated_at.by_month" }
         }
      }
   }
])

相关问题