R
Rishtaara
MongoDB Fundamentals
Lesson 15 of 40Article18 min

Find() & FindOne() Methods

find(filter) returns a cursor — an iterable handle to matching documents. findOne(filter) returns the first match as a single document or null. Both accept an optional projection as the second argument.

find() and findOne() basics

find(filter) returns a cursor — an iterable handle to matching documents. findOne(filter) returns the first match as a single document or null. Both accept an optional projection as the second argument.

Real-life example: find() is like searching a library catalog for all books by an author. findOne() stops at the first match — like looking up one student by roll number.

Basic find and findOne
use rishtaara

// All products
db.products.find()

// Filter — implicit AND between fields
db.products.find({ category: "electronics", price: { $lt: 1000 } })

// findOne — single document or null
db.students.findOne({ name: "Asha Khan" })
// { _id: ObjectId("..."), name: "Asha Khan", grade: 10, ... }

db.students.findOne({ name: "Nobody" })
// null

// Equality shorthand — these are equivalent
db.products.find({ category: "electronics" })
db.products.find({ category: { $eq: "electronics" } })

Projection — return only what you need

Projection controls which fields appear in results. Use 1 to include and 0 to exclude. You cannot mix inclusion and exclusion except for _id.

Real-life example: Projection is like photocopying only the name and grade columns from a report — not the entire page.

In APIs, always project only fields the client needs. Returning full documents wastes bandwidth and may leak internal fields.
Include and exclude fields
// Include name and price only; hide _id
db.products.find(
  { category: "electronics" },
  { name: 1, price: 1, _id: 0 }
)

// Exclude heavy fields from all products
db.products.find(
  {},
  { description: 0, images: 0, reviews: 0 }
)

// findOne with projection
db.students.findOne(
  { grade: 12 },
  { name: 1, "address.city": 1, _id: 0 }
)

sort(), skip(), and limit()

Chain sort(), skip(), and limit() on a find cursor for ordered and paginated results. Sort values: 1 ascending, -1 descending.

Real-life example: sort + skip + limit is like flipping to page 3 of a sorted phone book — skip the first 20 names, show the next 10.

  • Always sort before skip/limit for consistent pagination.
  • Large skip values are slow — use range queries on _id or createdAt for deep pagination.
  • Compound indexes should match your sort fields for performance.
Sort and pagination
// Cheapest electronics first, top 5
db.products
  .find({ category: "electronics" })
  .sort({ price: 1 })
  .limit(5)

// Most expensive products
db.products.find().sort({ price: -1 }).limit(10)

// Pagination: page 3, 10 per page (skip first 20)
const page = 3
const pageSize = 10
db.products
  .find({ category: "stationery" })
  .sort({ name: 1 })
  .skip((page - 1) * pageSize)
  .limit(pageSize)

// Sort by multiple fields: grade ascending, then name ascending
db.students.find().sort({ grade: 1, name: 1 })

countDocuments()

countDocuments(filter) counts documents matching a filter — accurate but scans matching docs. estimatedDocumentCount() is fast but approximate and ignores filters.

Real-life example: countDocuments is like asking 'How many grade-10 students?' — exact count. estimatedDocumentCount is like glancing at a 'approximately 500 students' sign.

Count matching documents
// Exact count with filter
db.products.countDocuments({ category: "electronics" })
// 47

db.students.countDocuments({ grade: { $gte: 10 }, active: true })
// 156

// Count documents with a specific field present
db.students.countDocuments({ email: { $exists: true } })

// Fast approximate total (no filter allowed)
db.products.estimatedDocumentCount()
// ~500 (may differ slightly from true count)

// Pagination helper
const total = db.products.countDocuments({ category: "electronics" })
const totalPages = Math.ceil(total / 10)
print("Total pages:", totalPages)