MongoDB填充聚合管道分页中缺少的日期

2vuwiymt  于 2022-11-03  发布在  Go
关注(0)|答案(1)|浏览(188)

我有这样的管道:

let pipeline = [

      {
        $group: {
          _id: "$date",
          tasks: { $push: "$$ROOT" },
        },
      },
      {
        $sort: { _id: -1 },
      },
      { 
        $skip: skip //4,8,12,16...etc
      },
      { 
        $limit: 4 
      }
    ];

    const aggregationData = await ScheduleTaskModel.aggregate(pipeline);

其中,我按日期对所有“任务”进行分组,并得到结果:

[
    {
        "_id": "2022-10-21T00:00:00.000Z",
        "tasks": [...tasks with this date]
    },
    {
        "_id": "2022-10-20T00:00:00.000Z",
        "tasks": [...tasks with this date]
    },
    {
        "_id": "2022-10-18T00:00:00.000Z",
        "tasks": [...tasks with this date]
    },
    {
        "_id": "2022-10-16T00:00:00.000Z",
        "tasks": [...tasks with this date]
    }
]

正如你所看到的,我在日期之间缺少了日期,这很好,我可以用简单的javascript操作结果,用空任务创建一个数组,其中包含上下日期之间的所有日期,并填充结果中也出现的日期。
问题在于,当我想使用$skip“分页”时,例如,如果跳到下一个4组,我无法判断下一个日期是否有任何文档,如果没有,我将得到如下所示的结果:

//FIRST RESULT WITH FILLED MISSING DATES
[
    {
        "_id": "2022-10-21T00:00:00.000Z",
        "tasks": [...tasks with this date]
    },
    {
        "_id": "2022-10-20T00:00:00.000Z",
        "tasks": [...tasks with this date]
    },
    {
        "_id": "2022-10-19T00:00:00.000Z",
        "tasks": [] //filled manually
    },
    {
        "_id": "2022-10-18T00:00:00.000Z",
        "tasks": [...tasks with this date]
    },
    {
        "_id": "2022-10-17T00:00:00.000Z",
        "tasks": [] //filled manually
    },
    {
        "_id": "2022-10-16T00:00:00.000Z",
        "tasks": [...tasks with this date]
    }
]

//LOST DAYS IN BETWEEN SKIPS

//SECOND RESULT WITH FILLED MISSING DATES
[
    {
        "_id": "2022-10-14T00:00:00.000Z",
        "tasks": [...tasks with this date]
    },
    {
        "_id": "2022-10-13T00:00:00.000Z",
        "tasks": [...tasks with this date]
    },
    {
        "_id": "2022-10-12T00:00:00.000Z",
        "tasks": [] //filled manually
    },
    {
        "_id": "2022-10-11T00:00:00.000Z",
        "tasks": [...tasks with this date]
    },
    {
        "_id": "2022-10-10T00:00:00.000Z",
        "tasks": [] //filled manually
    },
    {
        "_id": "2022-10-09T00:00:00.000Z",
        "tasks": [...tasks with this date]
    }
]

我仍然砰的一声我的头克服这一点,不幸的是$densify是不可能的,因为我使用的mongo版本之前,这是介绍

vatpfxk5

vatpfxk51#

如果您使用的是Mongo 5.1+版本,则可以使用新的$densify stage,它完全按照您的要求进行操作,如下所示:

db.collection.aggregate([
  {
    $group: {
      _id: "$date",
      tasks: {
        $push: "$$ROOT"
      }
    }
  },
  {
    $densify: {
      field: "_id",
      range: {
        step: 1,
        unit: "day",
        bounds: "full"
      }
    }
  },
  {
    $addFields: {
      tasks: {
        $ifNull: [
          "$tasks",
          []
        ]
      }
    }
  },
  {
    $sort: {
      _id: -1
    },

  },
  {
     $skip: n
  },
  {
    $limit: 4
  }
])

Mongo Playground
对于一个较小的Mongo版本,这变得更加困难,虽然技术上可能,我建议反对它,这里是一个玩具的例子,我如何实现它使用Mongo版本4.2语法,这是不可能实现的早期版本(除非你不愿意把_id字段转换成一个日期,因为返回的结果“日期”作为一个数字,然后你可以放弃$toDate转换)。
使用日期运算符(如$dateAdd$dateDiff)可以使此管道语法更加清晰,但这些操作符需要5.0以上的版本
问题是,您必须对整个结果集进行分组,以便对其进行迭代,并使用$reduce$map手动“填充”它,您可以想象这是非常低效的:

db.collection.aggregate([
  {
    $group: {
      _id: "$date",
      tasks: {
        $push: "$$ROOT"
      }
    }
  },
  {
    $sort: {
      _id: 1
    }
  },
  {
    $group: {
      _id: null,
      roots: {
        $push: "$$ROOT"
      }
    }
  },
  {
    $addFields: {
      roots: {
        $reduce: {
          input: "$roots",
          initialValue: {
            values: [],
            lastDate: null
          },
          in: {
            lastDate: "$$this._id",
            values: {
              $concatArrays: [
                "$$value.values",
                {
                  $map: {
                    input: {
                      $range: [
                        0,
                        {
                          $round: {
                            $divide: [
                              {
                                "$toDouble": {
                                  $subtract: [
                                    "$$this._id",
                                    {
                                      $ifNull: [
                                        "$$value.lastDate",
                                        {
                                          $subtract: [
                                            "$$this._id",
                                            86400000
                                          ]
                                        }
                                      ]
                                    }
                                  ]
                                }
                              },
                              86400000
                            ]
                          }
                        }
                      ]
                    },
                    as: "dayDiff",
                    in: {
                      $cond: [
                        {
                          $eq: [
                            "$$dayDiff",
                            0
                          ]
                        },
                        "$$this",
                        {
                          tasks: [],
                          _id: {
                            $toDate: {
                              $add: [
                                "$$this._id",
                                {
                                  $multiply: [
                                    {
                                      "$multiply": [
                                        86400000,
                                        "$$dayDiff"
                                      ]
                                    },
                                    -1
                                  ]
                                }
                              ]
                            }
                          }
                        }
                      ]
                    }
                  }
                }
              ]
            }
          }
        }
      }
    }
  },
  {
    $unwind: "$roots.values"
  },
  {
    $replaceRoot: {
      newRoot: "$roots.values"
    }
  },
  {
    $sort: {
      _id: -1
    }
  }
])

Mongo Playground

相关问题