Querying MongoDB: Filters, Projections, Sorting & Cursor Methods
Master MongoDB querying: comparison and logical operators, array queries, regex, projections, sort and pagination, and cursor methods. Lesson 5 of MongoDB & NoSQL Mastery.

The find() method is the gateway to MongoDB's data. A well-constructed query reads only the documents and fields it needs — reducing network transfer, memory pressure, and the work the application has to do. This lesson covers the full query language: every operator category, projections, cursor methods, and the patterns that keep queries fast.
Previous: Lesson 4 — Schema Design & Data Modelling
The Query Filter Document
A filter document is a JSON-like object whose fields match against document fields. An empty filter {} matches all documents.
// Equality filters
db.orders.find({ status: "shipped" })
db.orders.find({ status: "shipped", customerId: ObjectId("user_123") })
// Nested field query (dot notation)
db.products.find({ "specs.connectivity": "Bluetooth" })
// Array element query — matches if the array contains this value
db.products.find({ tags: "wireless" })Comparison Operators
| Operator | Meaning |
|---|---|
$eq | Equal (implicit when you write { field: value }) |
$ne | Not equal |
$gt | Greater than |
$gte | Greater than or equal |
$lt | Less than |
$lte | Less than or equal |
$in | Matches any value in array |
$nin | Matches no value in array |
// Orders placed in the last 7 days
const since = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)
db.orders.find({ createdAt: { $gte: since } })
// Products priced between £20 and £100
db.products.find({ price: { $gte: 20, $lte: 100 } })
// Orders in specific statuses
db.orders.find({ status: { $in: ["processing", "shipped"] } })
// Orders not yet delivered or cancelled
db.orders.find({ status: { $nin: ["delivered", "cancelled"] } })Logical Operators
// Implicit AND: all conditions in filter must match
db.products.find({ brand: "Logitech", price: { $lt: 100 } })
// Explicit $and (required when same field appears in both conditions)
db.products.find({ $and: [
{ price: { $gte: 40 } },
{ price: { $lt: 100 } }
]})
// $or: at least one condition matches
db.products.find({ $or: [
{ brand: "Logitech" },
{ brand: "Keychron" }
]})
// $nor: no conditions match
db.products.find({ $nor: [
{ stock: 0 },
{ price: { $gt: 200 } }
]})
// $not: negates a single operator expression
db.products.find({ price: { $not: { $gte: 100 } } })
// Combining $and and $or
db.products.find({
$and: [
{ price: { $lt: 150 } },
{ $or: [{ brand: "Logitech" }, { brand: "Keychron" }] }
]
})Element Operators
// Field exists (not absent)
db.products.find({ discount: { $exists: true } })
// Field does not exist
db.products.find({ discount: { $exists: false } })
// Field is null or missing
db.products.find({ discount: null })
// Match by BSON type
db.products.find({ price: { $type: "double" } })
db.products.find({ createdAt: { $type: "date" } })
db.products.find({ tags: { $type: "array" } })Array Operators
// Array contains a specific element
db.products.find({ tags: "wireless" })
// Array contains ALL specified elements (order-independent)
db.products.find({ tags: { $all: ["electronics", "wireless"] } })
// Array has a specific length
db.products.find({ tags: { $size: 3 } })
// $elemMatch — at least one array element matches ALL conditions
// (needed when multiple conditions must apply to the same element)
db.orders.find({
items: { $elemMatch: { productId: ObjectId("prod_001"), qty: { $gte: 2 } } }
})
// Querying by array index position
db.products.find({ "tags.0": "electronics" })Regular Expressions
// Case-insensitive name search
db.products.find({ name: { $regex: /keyboard/i } })
// Starts with "Wire"
db.products.find({ name: { $regex: /^Wire/ } })
// Ends with "Hub"
db.products.find({ name: /Hub$/ })
// Prefer regex anchors (^ and $) and indexes over unanchored patterns
// Only anchored regex patterns can use indexes efficientlyProjections: Returning Only What You Need
Projections dramatically reduce network transfer and deserialization cost in application code.
// Inclusion projection — return only listed fields (plus _id)
db.products.find({}, { name: 1, price: 1 })
// Exclude _id
db.products.find({}, { name: 1, price: 1, _id: 0 })
// Exclusion projection — return everything except listed fields
db.products.find({}, { specs: 0, tags: 0 })
// You cannot mix inclusion and exclusion (except for _id)
// This is an error:
// db.products.find({}, { name: 1, specs: 0 }) // ❌
// Project a specific array element by index
db.products.find({}, { "tags": { $slice: 1 } }) // first element only
// $elemMatch in projection — return only the first matching array element
db.orders.find(
{ "items.productId": ObjectId("prod_001") },
{ "items.$": 1 }
)Sorting, Limiting, and Skipping
// Sort ascending (1) or descending (-1)
db.products.find().sort({ price: 1 })
db.products.find().sort({ createdAt: -1 })
// Compound sort
db.products.find().sort({ brand: 1, price: -1 })
// Limit the result set
db.products.find().sort({ price: 1 }).limit(10)
// Offset-based pagination (use only for small collections)
const page = 3
const pageSize = 20
db.products.find().sort({ _id: 1 }).skip((page - 1) * pageSize).limit(pageSize)
// Cursor-based pagination (efficient for large collections)
const lastId = ObjectId("last_seen_id")
db.products.find({ _id: { $gt: lastId } }).sort({ _id: 1 }).limit(20)Cursor Methods
// Count without fetching documents
db.products.countDocuments({ brand: "Logitech" })
// Estimated count (uses metadata — very fast, not exact after unclean shutdown)
db.products.estimatedDocumentCount()
// Check if any matching document exists
db.products.findOne({ price: { $lt: 10 } }) !== null
// Iterate a cursor
const cursor = db.products.find({ tags: "electronics" })
while (cursor.hasNext()) {
const doc = cursor.next()
print(doc.name, doc.price)
}
// Convert cursor to array (use only when result set is bounded)
const results = db.products.find({ stock: { $gt: 0 } }).toArray()
// forEach
db.products.find({ stock: 0 }).forEach(doc => {
print("Out of stock:", doc.name)
})Distinct Values and Aggregation Shortcuts
// Get all unique values for a field
db.products.distinct("brand")
// Distinct values matching a filter
db.products.distinct("brand", { price: { $lt: 100 } })