Mongoose Queries, Chaining, and Lean Documents
Learners will chain Mongoose query helpers, use .lean() for raw POJO performance, and compare the query API to the native driver.
Mongoose Query Objects
When you call a Mongoose query method like User.find(), it returns a Query object rather than a Promise. This Query object is lazy—it does not execute until you explicitly call it with .then(), await, or .exec(). Before execution, you can chain additional query modifiers to build up the complete query. This chainable API is one of Mongoose's most ergonomic features.
const User = require('./models/user');
// This does NOT execute immediately — returns a Query object
const query = User.find({ active: true });
// Now execute it with await
const users = await query;
// Or chain modifiers before executing:
const result = await User.find({ active: true })
.sort({ createdAt: -1 })
.limit(10)
.select('name email -_id');
// select() projects fields: '+field' includes, '-field' excludesChaining Query Modifiers
Mongoose query modifiers like .sort(), .limit(), .skip(), .select(), and .populate() can be chained in any order before execution. The underlying Query object accumulates all modifiers and sends a single optimized query to MongoDB. This is functionally equivalent to passing options to the native driver's find(filter, options) but reads more naturally as a fluent builder.
const orders = await Order
.find({ status: 'completed', userId: currentUserId })
.sort({ createdAt: -1 }) // newest first
.skip(page * pageSize) // pagination offset
.limit(pageSize) // page size
.select('_id total status createdAt') // projection
.lean(); // return plain objects (discussed next)
console.log('Orders on this page:', orders.length);All lessons in this course
- Connecting With the Official Node.js Driver
- Mongoose Schemas, Models, and Virtuals
- Mongoose Queries, Chaining, and Lean Documents
- Mongoose Middleware: Pre and Post Hooks