javascript API

Pagination Helper Function

Reusable MongoDB pagination helper with sorting, filtering, search, and metadata for building paginated API responses.

Apex Logic 0 copies
javascript
/**
 * Paginate a Mongoose model with filtering, sorting, and search
 * @param {Model} model - Mongoose model
 * @param {Object} options - Pagination options
 * @returns {Object} - Paginated results with metadata
 */
async function paginate(model, options = {}) {
    const {
        page = 1,
        limit = 20,
        sort = '-createdAt',
        filter = {},
        search = '',
        searchFields = [],
        select = '',
        populate = '',
    } = options;

    const pageNum = Math.max(1, parseInt(page));
    const limitNum = Math.min(100, Math.max(1, parseInt(limit)));
    const skip = (pageNum - 1) * limitNum;

    // Build query
    const query = { ...filter };

    // Add text search if provided
    if (search && searchFields.length > 0) {
        query.$or = searchFields.map(field => ({
            [field]: { $regex: search, $options: 'i' }
        }));
    }

    // Parse sort string (e.g., '-createdAt,title' => { createdAt: -1, title: 1 })
    const sortObj = {};
    sort.split(',').forEach(field => {
        const trimmed = field.trim();
        if (trimmed.startsWith('-')) {
            sortObj[trimmed.slice(1)] = -1;
        } else {
            sortObj[trimmed] = 1;
        }
    });

    // Execute query and count in parallel
    const [docs, totalDocs] = await Promise.all([
        model.find(query)
            .sort(sortObj)
            .skip(skip)
            .limit(limitNum)
            .select(select)
            .populate(populate)
            .lean(),
        model.countDocuments(query)
    ]);

    const totalPages = Math.ceil(totalDocs / limitNum);

    return {
        data: docs,
        pagination: {
            page: pageNum,
            limit: limitNum,
            totalDocs,
            totalPages,
            hasNextPage: pageNum < totalPages,
            hasPrevPage: pageNum > 1,
            nextPage: pageNum < totalPages ? pageNum + 1 : null,
            prevPage: pageNum > 1 ? pageNum - 1 : null,
        }
    };
}

// Usage in a controller:
// const result = await paginate(Article, {
//     page: req.query.page,
//     limit: req.query.limit,
//     sort: '-publishedAt',
//     filter: { status: 'published' },
//     search: req.query.q,
//     searchFields: ['title', 'description'],
//     populate: 'author',
// });
// res.json(result);

module.exports = paginate;

Tags

pagination mongodb api helper

Related Snippets

javascript

JWT Authentication Middleware

javascript

MongoDB Connection with Retry

javascript

Express Global Error Handler

javascript

Rate Limiter with Sliding Window