Combine Search, Filtering and Pagination
A useful production-style list endpoint should support search, filters, sorting, and pagination together.
Example:
GET /api/v1/users?page=1&limit=10&search=john&role=user&sortBy=createdAt&order=desc
The request should:
- Parse query parameters.
- Validate the parameters.
- Build the MongoDB filter.
- Build the sorting options.
- Apply pagination.
- Retrieve matching records.
- Count matching records.
- Return pagination metadata.
The count query must use the same filter as the data query.
Mongoose lean() can reduce memory overhead when you do not need document methods, getters, or change tracking.
export async function listUsers({
page,
limit,
filter,
sort
}) {
const skip = (page - 1) * limit;
const [users, total] = await Promise.all([
User.find(filter)
.select('-password')
.sort(sort)
.skip(skip)
.limit(limit)
.lean(),
User.countDocuments(filter)
]);
return {
users,
total,
page,
limit,
totalPages: Math.ceil(total / limit)
};
}Combines filtering, sorting, pagination, and counting. lean() returns plain JavaScript objects rather than full Mongoose documents, which is useful for read-only results.
Combine query features into a consistent service interface.
Apply identical filters to data and count queries.
Use lean() when full Mongoose document behavior is unnecessary.