Home > database >  Mongodb lookup pagination
Mongodb lookup pagination

Time:05-16

I have a collection of categories, and each category has its array of _id from a different collection. My goal is to create an infinite scrolling by giving N records every time but from the end (the last record is always the most recent).

Category

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

Code:

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

So basically I slice the array, to get last N elements and then look them up on tracks collection. But I want to get N records from the end between specific range. For example, if I have 100 records, so giving the numbers 0, 25 will return the records from 100 (total records - 0) to 75 (100 - 25 - 0). 25, 25 should return 75 to 50. 50, 25 should return 50 (total records - 50) to 25 (100 - 50 - 25).

Or maybe there is a better way, but how do I achieve it from the end?

CodePudding user response:

You can so something like:

EDIT: to support edge cases:

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

This will return you a bulk of tracks with size bulkSize, starting from the end of the list for the first iteration and going backwards along the iterations. So if you have 100 tracks with index 0-99 and the bulkSize is 25, you will get tracks 75-99 for the first iteration, 50-74 for the 2nd iteration 25-49 for the 3rd... The avilableCount allows us to look at the edge cases: In the edge case where only a part of the bulk size is available it will return this part, and if non is available it will return [].

  • Related