Home > Software engineering >  Node Pagination and Filtering not working as Intended
Node Pagination and Filtering not working as Intended

Time:04-21

I am trying to implement Pagination and Filtering at the backend.

The input to this controller is Page number and Filtering conditions.

Controller:-

const getPosts = asyncHandler(async (req, res) => {
    const {
      page,
      statusFilter,
      typeFilter,
      sourceFilter,
    } = JSON.parse(req.query.filterData);
  
    
  
    var query = [
      {
        $addFields: {

          paramType: typeFilter,
          paramSource: sourceFilter,
          paramStatus: statusFilter,
        },
      },
      {
        $match: {
          $expr: {
            $and: [
              { user: req.user.id },
              {
                $or: [
                  {
                    $eq: ["$paramType", "All"],
                  },
                  {
                    $eq: ["$paramType", "$type"],
                  },
                ],
              },
              {
                $or: [
                  {
                    $eq: ["$paramSource", "All"],
                  },
                  {
                    $eq: ["$paramSource", "$source"],
                  },
                ],
              },
              {
                $or: [
                  {
                    $eq: ["$paramStatus", "All"],
                  },
                  {
                    $eq: ["$paramStatus", "$status"],
                  },
                ],
              },
            ],
          },
        },
      },
      {
        $project: {
          paramSource: false,
          paramType: false,
          paramStatus: false,
        },
      },
    ];
  
    //pagination
    const PAGE_SIZE = 5;
    const PAGE = parseInt(page) || 0;
  
    // aggregate query
    const aggregateQuery = await Post.aggregate([query]);

  
    const total = aggregateQuery.length;
  
  
    const Allposts = await Post.aggregate([query])
      .limit(PAGE_SIZE)
      .skip(PAGE_SIZE * PAGE)
      .sort({ createdAt: -1 });
  
    const totalPages = Math.ceil(total / PAGE_SIZE);
  
  
    res.status(200).json({ totalPages, Allposts });
  });

Problem:-

The pagination and filtering part works as intended but only for the first page, when I go to second page the Allposts object is empty.

Why is the Allposts object empty after first page?

Edit:-

Sample Data:-

{
    "_id" : 1,
    "type" : "Type A",
    "source" : "Source A",
    "status" : "Status A",
    "createdAt" : ISODate("2022-04-13T17:12:28.096Z"),
    "updatedAt" : ISODate("2022-04-13T17:12:28.096Z"),
    "__v" : 0
},
{
    "_id" : 2,
    "type" : "Type B",
    "source" : "Source C",
    "status" : "Status B",
    "createdAt" : ISODate("2022-04-13T17:12:28.096Z"),
    "updatedAt" : ISODate("2022-04-13T17:12:28.096Z"),
    "__v" : 0
},

{
    "_id" : 3,
    "type" : "Type A",
    "source" : "Source A",
    "status" : "Status A",
    "createdAt" : ISODate("2022-04-13T17:12:28.096Z"),
    "updatedAt" : ISODate("2022-04-13T17:12:28.096Z"),
    "__v" : 0
},

{
    "_id" : 4,
    "type" : "Type A",
    "source" : "Source C",
    "status" : "Status B",
    "createdAt" : ISODate("2022-04-13T17:12:28.096Z"),
    "updatedAt" : ISODate("2022-04-13T17:12:28.096Z"),
    "__v" : 0
}

Updated aggreation query:-

var query = [
    
    {
      $addFields: {
        paramType: typeFilter,
        paramSource: sourceFilter,
        paramStatus: statusFilter,
      },
    },
    {
      $match: {
        $expr: {
          $and: [
            { user: req.user.id },
            {
              $or: [
                {
                  $eq: ["$paramType", "All"],
                },
                {
                  $eq: ["$paramType", "$type"],
                },
              ],
            },
            {
              $or: [
                {
                  $eq: ["$paramSource", "All"],
                },
                {
                  $eq: ["$paramSource", "$source"],
                },
              ],
            },
            {
              $or: [
                {
                  $eq: ["$paramStatus", "All"],
                },
                {
                  $eq: ["$paramStatus", "$status"],
                },
              ],
            },
            
          ],
        },
      },
    },{ $sort : { createdAt : -1 } },
    {
      $project: {
        paramSource: false,
        paramType: false,
        paramStatus: false,
        createdAt : 1,
      },
    }
  ];

CodePudding user response:

If you want pagination total count with one query, you can do something like this:

db.collection.aggregate([
  {
    $addFields: {
      paramType: "typeFilter",
      paramSource: "sourceFilter",
      paramStatus: "statusFilter"
    }
  },
  {
    "$match": {
      // complete here
    }
  },
  {
    $setWindowFields: {
      output: {totalCount: {$count: {}}}}
  },
  {$sort: {createdAt: -1}},
  {$skip: PAGE_SIZE * PAGE},
  {$limit: PAGE_SIZE},
  {
    $facet: {
      results: [
        {
          $project: {
            // here put whatever you want to send to FE
            type: 1,
            source: 1,
          }
        }
      ],
      totalCount: [
        {$limit: 1},
        {$project: {totalCount: 1, _id: 0}}
      ]
    }
  }
])

As you can see on the playground

The $setWindowFields allows you to add the total count to all documents. $sort, $skip and $limit allow the pagination. The $facet allows you to get different outputs from the same documents.

  • Related