MongoDb - Return 来自嵌套数组末尾的 N 个元素的批量在每次调用时向后循环(分页)

MongoDb - Return bulks of N elements from the end of a nested array looping backwards at each call (pagination)

我有一个类别集合,每个类别都有来自不同集合的 _id 数组。 我的目标是通过每次提供 N 条记录但从最后开始(最后一条记录总是最新的)来创建无限滚动。

类别

{ 
    "_id" : ObjectId("625167ce3859b8465ccf69dc"), 
    "name" : {
        "en" : "Category #1"
    }, 
    "tracks" : [
        ObjectId("627f8475c229513838eed070"), 
        ObjectId("627f84b4c229513838eed074"), 
        ObjectId("6280ef548b97521c1f462266"), 
        ObjectId("6280ef68d147e83534f4ca03"), 
        ObjectId("6280ef6ad147e83534f4ca07"), 
        ObjectId("6280ef6bd147e83534f4ca0b"),
        // and so on..
    ]
}

代码:

categories
    .aggregate([
      {
        $match: {
          _id: ObjectId(categoryId),
        },
      },
      {
        $project: {
          tracks: {
            $slice: ["$tracks", -N],
          },
        },
      },
      {
        $lookup: {
          from: "tracks",
          as: "tracks",
          localField: "tracks",
          foreignField: "_id",
          pipeline: [{ $sort: { uploadedDate: -1 } }],
        },
      },
    ])

所以基本上我对数组进行切片,以获取最后 N 个元素,然后在 tracks 集合中查找它们。但我想从特定范围之间的末尾获取 N 条记录。 例如,如果我有 100 条记录,那么给定迭代次数 0 和批量大小:25,将返回最后 25 个元素(索引 75-99)。 在迭代 1 中,将返回下一个(向后移动)25 个元素(索引 50-74),依此类推...

你可以这样:

编辑: 支持边缘情况:

db.collection.aggregate([
  {
    $match: {_id: ObjectId("625167ce3859b8465ccf69dc")}
  },
  {
    $addFields: {
      avilableCount: {$max: [
        {$subtract: [{$size: "$tracks" }, bulkSize * iterations]},  
      0]}
    }
  },
   {
    $project: {
      tracks: {
        $cond: [{$eq: ["$avilableCount",  0]},
          [],
          {$slice: ["$tracks", {
                $max: [
                  {$subtract: [{$size: "$tracks"}, bulkSize * (iterations + 1)]}, 0]},
              {$min: [bulkSize , "$avilableCount"]}
            ]
          }
        ]
      }
    }
  }
])

Playground example

这将为您 return 提供大量大小为 bulkSize 的曲目,从第一次迭代的列表末尾开始,并沿着迭代向后移动。因此,如果您有 100 条索引为 0-99 且 bulkSize 为 25 的曲目,则第一次迭代将获得曲目 75-99,第二次迭代将获得曲目 50-74,第三次迭代将获得曲目 25-49... avilableCount 允许我们查看边缘情况: 在只有一部分批量大小可用的边缘情况下,它将 return 这部分,如果不可用,它将 return [].