PYP
PYP

Reputation: 125

Mongoose paginate - count total documents

I am using Mongoose paginate with search and filter queries for a schema called Thought. In my thought index .ejs template, I am displaying 40 records on each page using a forEach loop:

<% thoughts.docs.forEach(function(thought, i) { %>

There is a Show More button to click for the next 40 records:

            <div id="box-show-more" class="box-show-more">
                <button class="show-more" id="showMoreBtn" data-page="<%= thoughts.page + 1 %>">Show More</button>
            </div>

When a search/filter is applied on the author of the record, many of the authors have less than 40 records, but currently, the Show More button is still displayed. In my controller, the pagination is defined like this:

    const thoughts = await Thought.paginate(queryObject, {
        page: req.query.page || 1,
        limit: 40,
        sort: { 'createdAt': -1},
        populate: 'likes',
        collation: { locale: "en" }
    });

I want to include a count of the total documents, so I can add a wrapper around the Show More button like, 'if more than 40 records, display Show More button'. But I'm unsure how to include a count in the pagination query. In Mongoose docs a can see there is a field called 'totalDocs', but I'm unsure where to include this or how to return the value from it and use in my .ejs template.

Upvotes: 1

Views: 1982

Answers (2)

Joy Baruah
Joy Baruah

Reputation: 34

I made this Pagination Service which can be used with Mongo

import mongoose, { Model } from "mongoose";

/**
 * Represents a pagination service.
 * This class helps with managing pagination for a given Mongoose model.
 */

export interface PaginatedResponse {
  result: any[];
  hasNextPage: Boolean;
  hasPreviousPage: Boolean;
}

export default class PaginationService {
  private model: Model<any>;

  /**
   * Create a PaginationService instance.
   * @param {mongoose.Model} model - The Mongoose model to paginate.
   */

  constructor(model: Model<any>) {
    this.model = model;
  }

  private _page_size: number = 10; // Default size is 10

  /**
   * Gets or sets the page size.
   * @default 10
   */

  get page_size(): number {
    return this._page_size;
  }

  set page_size(newSize: number) {
    if (newSize <= 0) {
      throw new Error("Size must be a positive number");
    }
    this._page_size = newSize;
  }

  /**
   * Get Paginated Response
   * Next and Previous page as Boolean
   */

  async getPaginatedResponce(page: number): Promise<PaginatedResponse> {
    const totalDocumentsRecords = await this.model.countDocuments({});

    // Calculate the total number of pages
    const totalPages = Math.ceil(totalDocumentsRecords / this.page_size);

    // Determine if there's page
    const hasNextPage = page < totalPages;
    const hasPreviousPage = page > 1;

    const result = await this.model
      .find()
      .limit(this.page_size)
      .skip((page - 1) * this.page_size)
      .exec();

    const response: PaginatedResponse = {
      result,
      hasNextPage,
      hasPreviousPage,
    };

    return response;
  }
}

How to use it? here's how

import PaginationService, {
  PaginatedResponse,
} from "@/services/Pagination/Pagination";

const pagination = new PaginationService(anyMongoModel);
    pagination.page_size = 2;

let page = 1

let paginated_response: PaginatedResponse = await pagination.getPaginatedResponse(page);

You can tweek it to handle more scenarios.

Upvotes: 0

eol
eol

Reputation: 24565

Not sure which library/plugin for mongoose-pagination you are using, but considering this library it should be fairly straight-forward:

const result = await Thought.paginate(queryObject, {
      page: req.query.page || 1,
      limit: 40,     
      populate: 'likes'       
});

console.log(result.totalDocs);

The object returned from the paginate call will contain a property totalDocs which yields the total number of documents in collection that match your query.

Upvotes: 2

Related Questions