Section 5: MongoDB Basics

πŸ” Sorting & Pagination

Master data organization and efficient retrieval with interactive examples

πŸ“– The Tale of the Library Search Master

Imagine managing a library with 1 million books. A student asks: "Show me programming books from 2020+, over 300 pages, authors starting with 'J', in English or Spanish."

Without sorting & pagination: Manually check all 1 million books β†’ Takes YEARS!

With MongoDB: Get exactly 23 matching books in 0.5 seconds! ✨

πŸ“Š What is Sorting?

Sorting arranges documents in a specific order (ascending or descending) based on field values.

Sort Syntax:

db.collection.find().sort({ field: 1 })   // 1 = Ascending
db.collection.find().sort({ field: -1 })  // -1 = Descending

πŸ”€ Sorting Examples

Example 1: Sort by Age (Ascending)

db.users.find().sort({ age: 1 })
// Returns: youngest β†’ oldest

Example 2: Sort by Name (Descending)

db.users.find().sort({ name: -1 })
// Returns: Z β†’ A alphabetically

Example 3: Multiple Field Sort

db.users.find().sort({ city: 1, age: -1 })
// Sort by city (A→Z), then age (old→young) within each city
πŸ’‘ Pro Tip:

Always create indexes on fields you sort frequently for better performance!

πŸ“„ What is Pagination?

Pagination splits large result sets into smaller pages for efficient data retrieval.

Pagination Methods:

// Method 1: limit() - Get first N documents
db.users.find().limit(10)

// Method 2: skip() - Skip N documents
db.users.find().skip(20).limit(10)  // Page 3 (skip 20, show 10)

πŸ“‘ Pagination Examples

Example 1: First Page (10 items)

db.products.find().limit(10)
// Shows items 1-10

Example 2: Second Page

db.products.find().skip(10).limit(10)
// Shows items 11-20

Example 3: Calculate Skip for Any Page

const page = 5;
const pageSize = 10;
const skip = (page - 1) * pageSize;

db.products.find().skip(skip).limit(pageSize)
// Page 5 β†’ skip 40, show 10 (items 41-50)
⚠ Performance Warning:

skip() is slow for large offsets. For deep pagination, use cursor-based pagination instead!

🎯 Combining Sort + Pagination

The most powerful pattern combines filtering, sorting, and pagination:

// Get page 2 of premium users, sorted by age
db.users
  .find({ premium: true })         // Filter
  .sort({ age: -1 })                // Sort
  .skip(10)                         // Skip page 1
  .limit(10)                        // Page size
  
// Real e-commerce example
db.products
  .find({ 
    category: "electronics",
    price: { $lte: 1000 }
  })
  .sort({ rating: -1, price: 1 })  // Best rated, then cheapest
  .skip(20)
  .limit(10)

⭐ Best Practices

  1. Always index sorted fields for performance
  2. Use limit() to prevent returning too much data
  3. Avoid large skip() values - use cursor pagination for deep pages
  4. Sort on indexed fields to avoid in-memory sorts
  5. Use compound indexes for multi-field sorts
  6. Return total count separately for UI pagination
  7. Set reasonable page sizes (10-50 items)

πŸ’Ό Interview Questions & Answers

Q1 What is the difference between sort() and limit()? β–Ό

sort(): Orders documents by field values (ascending/descending)

limit(): Restricts the number of documents returned

Example:

db.users.find().sort({ age: -1 }).limit(5)
// Returns top 5 oldest users
Q2 Why is skip() slow for large offsets? β–Ό

Problem: MongoDB must scan and discard all skipped documents

Example: skip(10000) reads 10,000 docs just to throw them away!

Solution: Use cursor-based pagination:

// Instead of skip(1000)
db.products.find({ _id: { $gt: lastSeenId } }).limit(10)
Q3 How do you implement pagination efficiently? β–Ό

Method 1: Offset Pagination (for small datasets)

const page = 2, pageSize = 10;
db.items.find().skip((page-1)*pageSize).limit(pageSize)

Method 2: Cursor Pagination (for large datasets)

// Page 1
const results = db.items.find().sort({_id: 1}).limit(10)
const lastId = results[results.length - 1]._id

// Page 2
db.items.find({_id: {$gt: lastId}}).sort({_id: 1}).limit(10)
Q4 What happens if you sort without an index? β–Ό

Without Index: MongoDB performs an in-memory sort

  • Limited to 32MB of data
  • Very slow for large collections
  • Can cause query to fail if data exceeds 32MB

Solution: Create index on sort field:

db.users.createIndex({ age: 1 })  // Enables indexed sort
Q5 How do you get total count for pagination? β–Ό

Method 1: Separate count query

const total = await db.products.countDocuments({ category: "electronics" });
const items = await db.products.find({ category: "electronics" })
  .skip(20).limit(10).toArray();

Method 2: Aggregation pipeline

db.products.aggregate([
  { $match: { category: "electronics" } },
  { $facet: {
      total: [{ $count: "count" }],
      items: [{ $skip: 20 }, { $limit: 10 }]
  }}
])