Chapter 69: Node.js MongoDB Query

1. Quick mental model – How MongoDB queries work in Mongoose

  • .find() → returns many documents (array)
  • .findOne() → returns first matching document (or null)
  • .findById() → shortcut for _id lookup
  • .findOneAndUpdate(), .findOneAndDelete() → find + modify in one atomic operation
  • Queries are JavaScript objects — very natural
  • Mongoose adds:
    • schema validation
    • middleware (pre/post hooks)
    • population (like JOIN)
    • lean queries (faster read-only)
    • type safety with TypeScript

2. Project setup (modern & realistic)

Bash

tsconfig.json

JSON

package.json scripts

JSON

.env.example

text

3. MongoDB connection (production-safe)

src/config/mongodb.ts

TypeScript

src/config/env.ts

TypeScript

4. Realistic Mongoose model (Task)

src/models/task.model.ts

TypeScript

5. Insert some test data (once)

src/seed.ts (run once: npx tsx src/seed.ts)

TypeScript

Run:

Bash

Now we have real data to query!

6. Real query examples – from basic to advanced

6.1 Find all documents

TypeScript

Better: lean + select only needed fields

TypeScript

6.2 Find documents that match conditions

TypeScript

6.3 Find one document (.findOne(), .findById())

TypeScript

findById vs findOne

  • findById(id) → automatically converts string → ObjectId
  • findOne({ _id: id }) → you must do new mongoose.Types.ObjectId(id) yourself

6.4 Complex query – multiple conditions (AND / OR)

TypeScript

6.5 Text search (partial match on title & description)

First create text index (run once):

TypeScript

Then:

TypeScript

Much faster than { title: { $regex: search, $options: ‘i’ } }

6.6 Pagination (skip + limit)

TypeScript

Better performance tip Use cursor-based pagination (instead of skip) for large datasets:

TypeScript

Summary – MongoDB Find best practices in Node.js 2025–2026

Best Practice Why it matters Code pattern example
Use .lean() for read-only queries 2–5× faster – returns plain JS objects .find().lean()
Use .select() to limit fields Less data over network .select(‘title priority completed’)
Use .sort() explicitly Predictable order .sort({ createdAt: -1 })
Use text indexes for search Much faster than $regex schema.index({ title: ‘text’ })
Use .populate() for relations Joins referenced documents .populate(‘user’, ’email name’)
Use .skip() + .limit() for pagination Essential for lists .skip(offset).limit(pageSize)
Use cursor-based pagination for large data Avoid slow skip on big offsets { _id: { $gt: lastId } }
Always handle empty result Good API UX if (!task) throw new AppError(404, ‘Not found’)

Which direction would you like to go much deeper into next?

  • Login + JWT authentication with MongoDB
  • Full task CRUD (create/read/update/delete + ownership check)
  • Add pagination + filtering + sorting + full-text search
  • Add refresh tokens + cookie-based auth
  • Add unit & integration tests with Vitest
  • Docker + production deployment checklist

Just tell me what you want to build or understand next — I’ll continue with complete, secure, production-ready code and explanations. 😊

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *