Filtering and Sorting in Node.js APIs: A Complete Guide
List endpoints need filtering and sorting. Here is a complete guide.
Filtering and Sorting in Node.js APIs: A Complete Guide
List endpoints need filtering and sorting. Here is a complete guide.
Filtering
Use query params. Build a filter object based on which params are present.
const filter = {};
if (req.query.role) filter.role = req.query.role;
if (req.query.gender) filter.gender = req.query.gender;
if (req.query.status) filter.status = req.query.status;
if (req.query.minAge || req.query.maxAge) {
filter.age = {};
if (req.query.minAge) filter.age.$gte = parseInt(req.query.minAge);
if (req.query.maxAge) filter.age.$lte = parseInt(req.query.maxAge);
}
const users = await User.find(filter);
Whitelist Filter Fields
Do not let users set arbitrary filter fields. Whitelist the fields they can filter by:
const allowedFilters = ['role', 'gender', 'status', 'minAge', 'maxAge'];
const filter = {};
for (const key of allowedFilters) {
if (req.query[key] !== undefined) {
// build the filter
}
}
Prevents query injection and limits the surface.
Sorting
Use sortBy and order query params:
const sortBy = req.query.sortBy || 'createdAt';
const order = req.query.order === 'asc' ? 1 : -1;
const users = await User.find().sort({ [sortBy]: order });
Whitelist Sortable Fields
Do not let users sort by arbitrary fields. Whitelist the sortable fields:
const allowedSorts = ['createdAt', 'age', 'firstName'];
const sortBy = allowedSorts.includes(req.query.sortBy) ? req.query.sortBy : 'createdAt';
Prevents errors and potential abuse.
Field Selection
Let clients pick fields:
const fields = req.query.fields ? req.query.fields.split(',').join(' ') : null;
const users = await User.find().select(fields);
Whitelist selectable fields too, to prevent exposing sensitive data.
Combining: Filter, Sort, Paginate, Select
router.get('/users', asyncHandler(async (req, res) => {
const skip = parseInt(req.query.skip) || 0;
const limit = Math.min(parseInt(req.query.limit) || 20, 100);
const filter = buildFilter(req.query);
const sort = buildSort(req.query);
const select = buildSelect(req.query);
const [users, total] = await Promise.all([
User.find(filter).sort(sort).skip(skip).limit(limit).select(select).lean(),
User.countDocuments(filter)
]);
res.json({ data: users, total, skip, limit });
}));
Index for the Queries
Index the fields you filter and sort by. Use compound indexes for multi-field queries. Use explain() to verify.
The Takeaway
For list endpoints, support filtering (build a filter from whitelisted query params), sorting (whitelist sortable fields), field selection (whitelist selectable fields), and pagination. Combine all four in one query. Index the fields you filter and sort by. Use explain() to verify indexes are used.
Use query params. Build a filter object based on which params are present. Whitelist the fields users can filter by to prevent query injection. Pass the filter to Model.find(filter).
Use sortBy and order query params. Whitelist sortable fields to prevent errors and abuse. const sortBy = allowedSorts.includes(req.query.sortBy) ? req.query.sortBy : 'createdAt'. Use .sort({ [sortBy]: order }).
To prevent query injection (users setting arbitrary filter fields to probe your data) and errors (users sorting by a field that does not exist). Whitelisting limits the surface and keeps the API predictable.
Build a filter, sort, and select from query params. Then User.find(filter).sort(sort).skip(skip).limit(limit).select(select).lean(). Run find and countDocuments in parallel with Promise.all. Return { data, total, skip, limit }.
Use a fields query param. const fields = req.query.fields ? req.query.fields.split(',').join(' ') : null. Then .select(fields). Whitelist selectable fields to prevent exposing sensitive data like passwordHash.
Ready to master Node.js completely?
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.
Master Node.js
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course.

