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;