我有一个充满实体的集合,并且我正在使用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_MONTER键,即使是没有条目的月份

是否可以通过聚合直接实现这一点?现在我正在用光标遍历实体,但性能真的很差.

例如,给定以下示例文档:

[
  {
    "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
    },
}

推荐答案

你可以试试这个:

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

Mongodb相关问答推荐

基于另一子文档更改子文档的引用

MongoDB—基于数组中同一文档中的另一个字段更新字段

MongoDB合并按键更新值的对象数组

MongoDB v4.4聚合的$getfield替代方案

Mongoose 聚合和多级组

如何在 mongodb 中将一个方面的结果合并到一个有条件的列表中?

MongoDB 将 JSON 字符串转换为数组[{obj1},{obj2}]的实际对象

mongo.lock 文件有什么用?

SELECT 字段 AS `anothername` 的 mongodb 等效项

spring-data-mongo - 可选查询参数?

如何使用原子操作在一个文档中切换布尔字段?

MongoDB 3 Java判断集合是否存在

如何获取 Mongoid 文档的所有字段名称?

Mongoose 不创建新集合

我如何使用 Twitter 的流 api 中的推文并将它们存储在 mongodb 中

mongodb: UnknownError assertion src/mongo/db/server_options_helpers.cpp:355

MongoDB 连接字符串到副本集

如何通过键名从 mongoDB 中检索值?

带有 either or查询的mongoose findOne

Meteor 发布/订阅独特客户端集合的策略