Filters


Introduction to Filtering

Language Runtime Database

Client hits:

GET /api/products

All filters come through req.query.

Example:

/api/products?category=electronics&minPrice=100&page=2

Step 1 — Destructure Query Params


const {
  search,
  category,
  minPrice,
  maxPrice,
  inStock,
  page = 1,
  limit = 20,
  sort = 'createdAt', // default value if not provided
  order = 'desc',
} = req.query;

Step 2 — Build the Filter Object

const filter = {};

Only add properties if the client sends that value.

🔍 Search filter

if (search) {
  filter.$or = [
    { name: { $regex: search, $options: 'i' } },
    { description: { $regex: search, $options: 'i' } },
  ];
}
  • $or → match either name OR description
  • $regex → partial text match (like SQL LIKE)
  • $options: 'i' → case-insensitive

📂 Category filter

if (category) {
  filter.category = category;
}

💰 Price range filter

if (minPrice || maxPrice) {
  filter.price = {};

  if (minPrice) filter.price.$gte = Number(minPrice); // greater than or equal
  if (maxPrice) filter.price.$lte = Number(maxPrice); // less than or equal
}
  • $gte → greater than or equal
  • $lte → less than or equal
  • Number() converts "100"100
  • Either value can be sent independently

✅ Boolean filter

if (inStock !== undefined) {
  filter.inStock = inStock === 'true';
}

Query params are strings, so:

"true" === 'true' → true

Step 3 — Sorting

const sortObj = {
  [sort]: order === 'asc' ? 1 : -1,
};
  • MongoDB uses:

    • 1 → ascending
    • -1 → descending

Example:

sort=price&order=asc → { price: 1 }

Step 4 — Pagination

const skip = (Number(page) - 1) * Number(limit);
pagelimitskip
1200
22020
32040

Skip already-seen records to get the correct page.


Step 5 — Query the Database

const [items, total] = await Promise.all([
  Product.find(filter)
    .sort(sortObj)
    .skip(skip)
    .limit(Number(limit)),
  Product.countDocuments(filter),
]);
  • Promise.all runs both queries in parallel (faster)
  • First query → fetch data
  • Second query → total count (needed for pagination UI)

Step 6 — Send Response

res.json({
  data: items,
  pagination: {
    total,
    page: Number(page),
    limit: Number(limit),
    totalPages: Math.ceil(total / limit),
  },
});

Overview

Client sends:

?search=phone&category=electronics&minPrice=100&page=2

Filter becomes:

{
  $or: [
    { name: /phone/i },
    { description: /phone/i }
  ],
  category: "electronics",
  price: { $gte: 100 }
}