Documentation
Use the package
🔍 Querying
The APIFeatures class provides powerful querying capabilities for your CRUD APIs, allowing you to filter, sort, search, paginate, and populate your data efficiently. Below, each feature is explained in detail with practical examples using our Product model.
Filtering
Filtering allows you to retrieve documents that match specific criteria. There are two types: basic filtering for exact matches and advanced filtering for range queries.
Basic Filtering
For fields that accept multiple values (like enums, arrays, or booleans), use comma-separated values. This uses MongoDB's $in operator to match any of the provided values.
Explanation: This is useful for filtering by categories, statuses, tags, or any field where you want to include multiple options. The query parameter value is split by commas and converted to an $in array.
Example: Get products that are active.
GET /products?isActive=true
Example: Get products with specific tags.
GET /products?tags=electronics,gadgets,smartphone
Example: Get products from specific brands.
GET /products?brand=Apple,Samsung,Sony
In our Product model, you can filter by:
- Booleans:
isActive - Arrays:
tags,images - Strings:
brand,name,description - Relationships:
category(category ID)
Advanced Filtering
For range queries and comparisons, use bracket notation with MongoDB comparison operators:
[gte]- greater than or equal ($gte)[gt]- greater than ($gt)[lte]- less than or equal ($lte)[lt]- less than ($lt)
Explanation: These operators allow precise range filtering on numeric or date fields. The bracket notation [operator] is parsed to extract the field name and apply the corresponding MongoDB operator.
Example: Get products with price between $100 and $500.
GET /products?price[gte]=100&price[lte]=500
Example: Get products with high ratings (above 4.0) and good stock (more than 10).
GET /products?rating[gte]=4.0&stock[gt]=10
Example: Get products created in the last 30 days.
GET /products?createdAt[gte]=2024-01-01
Note: Date fields should be in ISO format (YYYY-MM-DDTHH:mm:ss.sssZ). Our Product model has automatic createdAt/updatedAt timestamps.
You can combine multiple operators on the same field or different fields:
GET /products?price[gte]=50&price[lte]=200&rating[gte]=3.5&stock[gte]=5
Sorting
Sort your results by one or more fields to control the order of returned documents.
Explanation: Separate multiple fields with commas. Prefix a field with - for descending order. If no sort is specified, results default to -createdAt (newest first). This uses MongoDB's sort() method.
Example: Sort products by price ascending.
GET /products?sort=price
Example: Sort by rating descending, then by stock descending.
GET /products?sort=-rating,-stock
Example: Sort by newest products first.
GET /products?sort=-createdAt
For our Product model, you can sort by fields such as name, price, stock, rating, createdAt, and updatedAt.
Limiting Fields
Control which fields are included or excluded in the response to optimize payload size and hide sensitive data.
Explanation: Use a comma-separated list of field names. By default, the __v field (Mongoose version key) is excluded. Prefix fields with - to exclude them instead of including only them. This uses MongoDB's select() method.
Example: Only return essential fields for a product list view.
GET /products?fields=name,price,images,rating,brand
Example: Return all fields except description for performance.
GET /products?fields=-description,-__v
Example: Get only catalog essentials.
GET /products?fields=name,price,stock,rating
Pagination
Split large result sets into manageable pages for better performance and user experience.
Explanation: Use page (default: 1) and limit (default: 10) parameters. The API calculates the skip value as (page - 1) * limit. The response includes pagination metadata like total count, current page, total pages, and next/previous page numbers.
Example: Get the second page with 20 products per page.
GET /products?page=2&limit=20
This skips the first 20 documents and returns documents 21-40.
Example: Get active products with pagination.
GET /products?isActive=true&page=1&limit=12
Searching
Perform case-insensitive text searches across multiple fields using regex.
Explanation: The format is ?search=searchTerm:field1,field2,field3. The search term is applied as a regex pattern to each specified field, combined with MongoDB's $or operator. This is efficient when fields have text indexes.
Example: Search for "laptop" in the name or description fields.
GET /products?search=laptop:name,description
Example: Search across name, description, and brand.
GET /products?search=wireless:name,description,brand
Example: Search by brand for specific companies.
GET /products?search=apple:brand
This creates: { $or: [{ name: { $regex: 'laptop', $options: 'i' } }, { description: { $regex: 'laptop', $options: 'i' } }] }
In our Product model, you can search in name, description, brand, or array fields like tags.
Population
Populate referenced documents to include related data in your response, avoiding multiple queries.
Explanation: Start by passing the reference path. If you do not specify fields, the populated document includes all fields from the related model. You can then add a field list to limit the response and reduce payload size. Use | to separate multiple population paths. Population occurs after filtering, sorting, etc., for optimal performance.
Format without field selection: ?populate=path
Example: Populate the category field and return all category fields.
GET /products?populate=category
Format: ?populate=path:field1,field2,field3
Example: Populate the category field, but only include name and description from the Category model.
GET /products?populate=category:name,description
Example: Get category details and image for product displays.
GET /products?populate=category:name,description,image,isActive
Format for multiple populations: ?populate=path1|path2:field1,field2
Example: Populate multiple relationships at once. Paths without field selection return all fields; paths with :field1,field2 return only the selected fields.
GET /products?populate=category|supplier:name,email
Example: Populate multiple paths and keep the category payload small.
GET /products?populate=category:name,description|supplier:name,email|owner
In our Product model, category references the Category model. Using ?populate=category returns the full populated category document. Adding :field1,field2 limits the populated data to only those fields.
Example: Combine with other queries - get active products from active categories.
GET /products?isActive=true&populate=category:isActive&category.isActive=true