MongoDB query filters match documents using nested objects and $-prefixed operators like $gte, $in, $or, and $regex. Writing clean filter objects—and validating user-supplied request data—gives you expressive search queries while defending against NoSQL operator injection.
Combine equality matches with range, membership, and logical operators to filter collections precisely.
| Operator | Meaning | Example |
|---|---|---|
$gt / $gte |
Greater than / or equal | { price: { $gte: 20, $lte: 100 } } |
$lt / $lte |
Less than / or equal | { stock: { $lt: 5 } } |
$in / $nin |
Matches any value in array | { status: { $in: ['paid', 'shipped'] } } |
$ne |
Not equal | { role: { $ne: 'banned' } } |
$or / $and |
Logical OR / AND array | { $or: [{ featured: true }, { rating: { $gte: 4.5 } }] } |
import { MongoClient } from 'mongodb';
function escapeRegex(text) {
return text.replace(/[.*+?^${}()|[\]\]/g, '\$&');
}
async function searchProducts(productsCollection, { keyword, minPrice, categories }) {
const filter = {};
if (typeof keyword === 'string' && keyword.trim() !== '') {
filter.name = { $regex: escapeRegex(keyword.trim()), $options: 'i' };
}
if (typeof minPrice === 'number') {
filter.price = { $gte: minPrice };
}
if (Array.isArray(categories) && categories.length > 0) {
filter.category = { $in: categories.map(String) };
}
return productsCollection.find(filter).limit(25).toArray();
}
If an attacker sends JSON {"email": {"$ne": null}} to a login route and your code passes req.body.email straight into users.findOne({ email: req.body.email }), MongoDB matches the very first user in the database! Always validate and cast inputs to primitives (String(req.body.email) or Zod schemas) before placing them into query filters.
req.body objects into findOne(): An object containing {"$gt": ""} turns an equality check into an operator match. Enforce string/number types first.$regex without escaping: Typing ( or [ in a search box crashes $regex with a regex syntax error unless escaped with escapeRegex().$regex on huge collections: Leading-wildcard regexes cannot use standard B-tree indexes efficiently; consider MongoDB Atlas Search or $text indexes for full-text search.Use { deletedAt: { $exists: false } } or { deletedAt: null } (note that $exists: false matches only documents missing the field, whereas null matches both missing fields and explicit null values).
Use quoted dot notation, such as { 'address.city': 'Dhaka' }.
To match documents whose tags array contains 'nodejs', pass { tags: 'nodejs' } directly, or { tags: { $all: ['nodejs', 'mysql'] } } when all listed tags must be present.
Sign in to track your learning journey, earn industry-recognized certificates, and join our elite developer community.
Quick Access With
Experiment with the code from this lesson in our interactive playground.