Section 13: MongoDB vs MySQL

βš–οΈ MongoDB vs SQL Interview Questions

Compare NoSQL and Relational Database Concepts

🎯 About MongoDB vs SQL Questions

These comparison questions are extremely common in interviews. Interviewers want to see if you understand the fundamental differences and can make informed decisions about when to use each database type.

πŸ’‘ What Interviewers Look For:
  • Conceptual Understanding: Not just memorized facts, but deep comprehension
  • Trade-off Analysis: Can you articulate pros/cons of each approach
  • Real-world Application: Practical experience with both systems
  • Nuanced Thinking: Avoid "X is always better" - it depends on context
  • Migration Experience: Have you moved between systems?
25
Questions
80%
Interview Frequency
All Levels
Seniority Range
⚠️ Common Mistakes to Avoid:
  • Saying "NoSQL is better" or "SQL is better" without context
  • Not understanding that MongoDB supports transactions (since 4.0)
  • Thinking schemas in MongoDB are always schemaless
  • Claiming SQL can't scale horizontally
  • Ignoring hybrid approaches and polyglot persistence

πŸ” Core Differences

Fundamental architectural and conceptual differences.

Q1 Easy Google Amazon
What are the fundamental differences between MongoDB and SQL databases? Explain the data model, schema, and query language differences.

βœ“ Complete Answer:

Aspect MongoDB SQL Databases
Data Model Document-oriented (JSON-like BSON) Table-based (rows and columns)
Schema Flexible/Dynamic schema Fixed/Rigid schema
Relationships Embedded documents or references Foreign keys & JOINs
Query Language JSON-based query syntax SQL (Structured Query Language)
Scaling Built for horizontal (sharding) Traditionally vertical
Terminology Database β†’ Collection β†’ Document β†’ Field Database β†’ Table β†’ Row β†’ Column
Data Model Example:
MongoDB Document:
{
  _id: ObjectId("507f1f77bcf86cd799439011"),
  name: "Alice Johnson",
  email: "alice@example.com",
  age: 28,
  address: {
    street: "123 Main St",
    city: "San Francisco",
    zip: "94102"
  },
  orders: [
    { orderId: 101, total: 150, date: ISODate("2024-01-15") },
    { orderId: 102, total: 220, date: ISODate("2024-02-20") }
  ]
}

// Single document contains nested data
// No need for JOIN operations
SQL Tables:
-- Users table
CREATE TABLE users (
  id INT PRIMARY KEY,
  name VARCHAR(100),
  email VARCHAR(100),
  age INT
);

-- Addresses table
CREATE TABLE addresses (
  id INT PRIMARY KEY,
  user_id INT FOREIGN KEY REFERENCES users(id),
  street VARCHAR(200),
  city VARCHAR(100),
  zip VARCHAR(10)
);

-- Orders table
CREATE TABLE orders (
  id INT PRIMARY KEY,
  user_id INT FOREIGN KEY REFERENCES users(id),
  total DECIMAL(10,2),
  date DATE
);

-- Requires JOINs to get complete user data
SELECT u.*, a.*, o.*
FROM users u
LEFT JOIN addresses a ON u.id = a.user_id
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.id = 1;
Key Conceptual Differences:
1. Schema Flexibility
  • MongoDB: Documents in same collection can have different fields
  • SQL: All rows must conform to table schema
// MongoDB - Different structures allowed
db.users.insertMany([
  { name: "Alice", email: "alice@example.com" },
  { name: "Bob", email: "bob@example.com", phone: "555-1234" },
  { name: "Charlie", age: 30, address: { city: "NYC" } }
])
// All valid in same collection!

-- SQL - Must ALTER TABLE to add columns
INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com');
-- Can't insert phone without adding column first
ALTER TABLE users ADD COLUMN phone VARCHAR(20);
INSERT INTO users (name, email, phone) VALUES ('Bob', 'bob@example.com', '555-1234');
2. Data Relationships
  • MongoDB: Embeds related data OR uses references
  • SQL: Normalizes data across tables with foreign keys
🎯 Interview Tip:

Don't just list differences. Explain WHEN each approach is better. For example: "MongoDB's flexible schema is ideal for rapidly evolving applications, while SQL's rigid schema enforces data integrity for financial systems."

Q2 Medium Meta Netflix
When would you choose MongoDB over SQL? Give specific use cases with reasoning.

βœ“ Complete Answer:

Choose MongoDB When:

1. Rapid Development & Iteration

Use Case: Startup building MVP, requirements changing weekly

  • No time for schema migrations every sprint
  • Product features evolving based on user feedback
  • Need to add fields without downtime

Example: Social media platform adding new user profile fields (bio, interests, badges) without altering database schema.

2. Hierarchical/Nested Data

Use Case: Content management system, e-commerce product catalog

  • Data naturally hierarchical (JSON-like)
  • Would require many JOINs in SQL
  • Read entire object in one query
// E-commerce product with variants
{
  productId: "P123",
  name: "T-Shirt",
  category: "Clothing",
  variants: [
    { size: "S", color: "Red", sku: "TS-S-R", price: 19.99, stock: 50 },
    { size: "M", color: "Red", sku: "TS-M-R", price: 19.99, stock: 30 },
    { size: "L", color: "Blue", sku: "TS-L-B", price: 19.99, stock: 20 }
  ],
  reviews: [
    { user: "Alice", rating: 5, comment: "Great fit!" },
    { user: "Bob", rating: 4, comment: "Nice quality" }
  ]
}

// Single query gets complete product data
// SQL would need 3+ tables and JOINs
3. High Write Volume / Real-time Analytics

Use Case: IoT sensor data, logging systems, clickstream analytics

  • Thousands of writes per second
  • Time-series data with flexible attributes
  • Need horizontal scaling (sharding)

Example: Smart home system collecting sensor data from millions of devices, each with different sensor types.

4. Geospatial Applications

Use Case: Food delivery, ride-sharing, real estate search

  • Built-in geospatial indexes (2dsphere)
  • Native GeoJSON support
  • Efficient proximity queries
// Find restaurants within 5km
db.restaurants.find({
  location: {
    $near: {
      $geometry: { type: "Point", coordinates: [-122.4194, 37.7749] },
      $maxDistance: 5000
    }
  }
})
5. Horizontal Scaling Requirements

Use Case: Large-scale applications (100M+ users)

  • Dataset too large for single server
  • Need to distribute across multiple machines
  • Automatic sharding built-in

Choose SQL When:

1. Complex Transactions

Use Case: Banking, financial systems, inventory management

  • Multi-table ACID transactions critical
  • Strong consistency required
  • Complex business rules
2. Complex Analytical Queries

Use Case: Business intelligence, reporting systems

  • Complex JOINs across many tables
  • Aggregations with GROUP BY, HAVING
  • SQL's mature query optimization
3. Mature Ecosystem Needed

Use Case: Enterprise applications, legacy system integration

  • Decades of tooling and expertise
  • ORM support (Hibernate, Entity Framework)
  • Integration with BI tools
πŸ’‘ Real Interview Example:

"We're building a content management system for a news website. Which database would you choose?"

Good Answer: "I'd choose MongoDB because:

  • Articles have varying structure (text, images, videos, polls)
  • Need to iterate quickly on article metadata
  • Reads heavily outweigh writes (can scale with replica sets)
  • Natural document structure matches article content

However, if the system required complex analytics across authors, categories, and engagement metrics with many JOINs, SQL might be better for the analytics portion (polyglot persistence)."

Q3 Medium Amazon Uber
Compare ACID properties in MongoDB vs SQL databases. Does MongoDB support transactions?

βœ“ Complete Answer:

ACID Recap:

  • Atomicity: All operations succeed or all fail
  • Consistency: Database moves from valid state to valid state
  • Isolation: Concurrent transactions don't interfere
  • Durability: Committed data persists even after crashes
Property SQL Databases MongoDB
Atomicity Multi-table transactions Single document always atomic
Multi-document since v4.0
Consistency Enforced via constraints Eventual consistency (tunable)
Strong consistency with write/read concern
Isolation Multiple isolation levels Read uncommitted (default)
Snapshot isolation in transactions
Durability Write-ahead logging (WAL) Journal + write concern
MongoDB Transaction Support:
βœ“ YES - MongoDB Supports Transactions (Since v4.0)

Common misconception: People think MongoDB doesn't support transactions. It does!

  • v4.0 (2018): Multi-document transactions in replica sets
  • v4.2 (2019): Distributed transactions across shards
  • Snapshot isolation: Transactions see consistent snapshot of data
// MongoDB Multi-Document Transaction
const session = client.startSession();

try {
  session.startTransaction();
  
  // Transfer $100 from Alice to Bob
  await accounts.updateOne(
    { name: "Alice" },
    { $inc: { balance: -100 } },
    { session }
  );
  
  await accounts.updateOne(
    { name: "Bob" },
    { $inc: { balance: 100 } },
    { session }
  );
  
  await session.commitTransaction();
  console.log("Transfer successful");
  
} catch (error) {
  await session.abortTransaction();
  console.log("Transfer failed, rolled back");
} finally {
  session.endSession();
}
-- SQL Transaction (PostgreSQL)
BEGIN TRANSACTION;

UPDATE accounts SET balance = balance - 100 WHERE name = 'Alice';
UPDATE accounts SET balance = balance + 100 WHERE name = 'Bob';

COMMIT;  -- or ROLLBACK on error
Key Differences:
1. Single Document Atomicity

MongoDB Advantage: Single document operations are ALWAYS atomic

// Atomic update on embedded document
db.accounts.updateOne(
  { _id: userId },
  {
    $inc: { balance: 100 },
    $push: { 
      transactions: {
        amount: 100,
        date: new Date(),
        type: "deposit"
      }
    }
  }
)

// Both balance update AND transaction push succeed or fail together
// No transaction needed!

In SQL, this would require a transaction across 2 tables (accounts + transactions).

2. Transaction Performance
  • SQL: Highly optimized, decades of tuning
  • MongoDB: Newer, some performance overhead
  • Best Practice: Design MongoDB schemas to minimize multi-doc transactions
⚠️ Important Nuances:
  • Write Concern: MongoDB's "durability" depends on write concern setting
  • w:1 (default): Acknowledged by primary only (could lose data on crash)
  • w:"majority": Replicated to majority (durable like SQL)
  • Consistency: MongoDB is eventually consistent by default, but configurable
🎯 Interview Gold:

Don't say "MongoDB doesn't support ACID" - that's outdated (pre-2018)! Explain that:

  • Single document ops are always ACID
  • Multi-document transactions supported since v4.0
  • ACID properties are tunable via write/read concerns
  • MongoDB trades some ACID guarantees for performance/availability by default

πŸ“ Schema Design

Data modeling and schema design philosophies.

Q4 Hard Google Meta
Explain normalization in SQL vs denormalization in MongoDB. When do you embed vs reference?

βœ“ Complete Answer:

SQL Normalization Philosophy:

Eliminate redundancy by splitting data across multiple tables.

-- Normalized SQL Design (3NF)
-- Users table
users:
  id | name        | email
  1  | Alice       | alice@example.com
  2  | Bob         | bob@example.com

-- Orders table
orders:
  id | user_id | total | date
  101| 1       | 150   | 2024-01-15
  102| 1       | 220   | 2024-02-20
  103| 2       | 180   | 2024-03-10

-- Products table
products:
  id | name      | price
  1  | Widget    | 50
  2  | Gadget    | 75

-- Order_Items table (junction table)
order_items:
  order_id | product_id | quantity
  101      | 1          | 3
  102      | 2          | 2
  103      | 1          | 1

Benefits:
βœ“ No data redundancy
βœ“ Easy to update (change product price once)
βœ“ Data integrity enforced

Drawbacks:
βœ— Requires complex JOINs (4 tables to get user's orders with products)
βœ— JOIN operations expensive

MongoDB Denormalization Philosophy:

Store data together that's accessed together (optimize for reads).

// Denormalized MongoDB Design
{
  _id: 1,
  name: "Alice",
  email: "alice@example.com",
  orders: [
    {
      orderId: 101,
      total: 150,
      date: ISODate("2024-01-15"),
      items: [
        { product: "Widget", price: 50, quantity: 3 }
      ]
    },
    {
      orderId: 102,
      total: 220,
      date: ISODate("2024-02-20"),
      items: [
        { product: "Gadget", price: 75, quantity: 2 }
      ]
    }
  ]
}

Benefits:
βœ“ Single query gets all data
βœ“ No JOINs needed
βœ“ Atomic updates on user document

Drawbacks:
βœ— Data duplication (product info repeated)
βœ— If product price changes, must update many documents
βœ— Document size can grow large
Embed vs Reference Decision Framework:
βœ“ EMBED When:
  • One-to-Few: User has 1-10 addresses
  • Data accessed together: Always show addresses with user
  • Bounded growth: Won't exceed 16MB document limit
  • Child data specific to parent: Order items belong only to that order
// Embed addresses
{
  _id: userId,
  name: "Alice",
  addresses: [
    { type: "home", street: "123 Main St", city: "SF" },
    { type: "work", street: "456 Oak Ave", city: "SF" }
  ]
}
βœ— REFERENCE When:
  • One-to-Many (unbounded): Blog post has 10,000+ comments
  • Many-to-Many: Students and courses
  • Data accessed independently: Products queried separately from orders
  • Frequent updates to child: Product prices change often
// Reference products
// Products collection
{
  _id: "product-1",
  name: "Widget",
  price: 50,
  stock: 100
}

// Orders collection (references product)
{
  _id: "order-101",
  userId: "user-1",
  items: [
    { productId: "product-1", quantity: 3 }  // Reference, not embed
  ]
}

// Lookup when needed
db.orders.aggregate([
  { $lookup: {
      from: "products",
      localField: "items.productId",
      foreignField: "_id",
      as: "productDetails"
    }
  }
])
Real-World Example: Blog System
βœ“ Embed Comments (Good for small blogs)
{
  _id: "post-1",
  title: "MongoDB Basics",
  content: "...",
  comments: [
    { user: "Alice", text: "Great post!", date: "..." },
    { user: "Bob", text: "Very helpful", date: "..." }
  ]
}

Good when:
- Few comments per post (< 100)
- Comments always shown with post
- Comments don't change often
βœ— Reference Comments (Better for popular blogs)
// Posts collection
{ _id: "post-1", title: "MongoDB", ... }

// Comments collection
{ _id: "c1", postId: "post-1", user: "Alice", ... }
{ _id: "c2", postId: "post-1", user: "Bob", ... }

Better when:
- Thousands of comments per post
- Pagination needed
- Comments have complex queries
πŸ’‘ Interview Strategy:

When asked about schema design, always:

  1. Ask about access patterns: "How will data be queried?"
  2. Ask about scale: "How many related items expected?"
  3. Ask about update frequency: "Does child data change often?"
  4. Explain trade-offs of your choice

πŸ”Ž Query Comparison

How queries differ between MongoDB and SQL.

Q5 Medium Amazon
Compare equivalent queries in MongoDB and SQL. Show examples of SELECT, JOIN, and aggregation operations.

βœ“ Complete Answer:

Example 1: Simple SELECT
SQL:
SELECT name, email, age
FROM users
WHERE age >= 25 AND city = 'San Francisco'
ORDER BY name ASC
LIMIT 10;
MongoDB:
db.users.find(
  { age: { $gte: 25 }, city: "San Francisco" },  // WHERE clause
  { name: 1, email: 1, age: 1, _id: 0 }          // SELECT clause (projection)
)
.sort({ name: 1 })                                // ORDER BY
.limit(10);                                       // LIMIT
Example 2: JOIN Operations
SQL:
SELECT u.name, u.email, o.id AS order_id, o.total, o.date
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.age > 25;
MongoDB ($lookup - similar to LEFT JOIN):
db.users.aggregate([
  { $match: { age: { $gt: 25 } } },              // WHERE clause
  {
    $lookup: {
      from: "orders",                             // JOIN orders table
      localField: "_id",                          // users._id
      foreignField: "userId",                     // orders.userId
      as: "userOrders"                           // Result array
    }
  },
  {
    $project: {                                   // SELECT clause
      name: 1,
      email: 1,
      "userOrders.orderId": 1,
      "userOrders.total": 1,
      "userOrders.date": 1
    }
  }
]);
Example 3: Aggregation (GROUP BY)
SQL:
SELECT city, COUNT(*) AS user_count, AVG(age) AS avg_age
FROM users
GROUP BY city
HAVING COUNT(*) > 10
ORDER BY user_count DESC;
MongoDB:
db.users.aggregate([
  {
    $group: {
      _id: "$city",                               // GROUP BY city
      user_count: { $sum: 1 },                    // COUNT(*)
      avg_age: { $avg: "$age" }                   // AVG(age)
    }
  },
  {
    $match: { user_count: { $gt: 10 } }          // HAVING
  },
  {
    $sort: { user_count: -1 }                     // ORDER BY
  }
]);
Example 4: Complex Aggregation with Multiple JOINs
SQL:
SELECT 
  u.name,
  COUNT(DISTINCT o.id) AS total_orders,
  SUM(o.total) AS total_spent,
  AVG(o.total) AS avg_order_value
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE o.date >= '2024-01-01'
GROUP BY u.id, u.name
HAVING COUNT(o.id) >= 3
ORDER BY total_spent DESC
LIMIT 5;
MongoDB:
db.users.aggregate([
  {
    $lookup: {
      from: "orders",
      localField: "_id",
      foreignField: "userId",
      as: "orders"
    }
  },
  {
    $unwind: "$orders"                            // Flatten array
  },
  {
    $match: {
      "orders.date": { $gte: ISODate("2024-01-01") }
    }
  },
  {
    $group: {
      _id: "$_id",
      name: { $first: "$name" },
      total_orders: { $sum: 1 },
      total_spent: { $sum: "$orders.total" },
      avg_order_value: { $avg: "$orders.total" }
    }
  },
  {
    $match: { total_orders: { $gte: 3 } }
  },
  {
    $sort: { total_spent: -1 }
  },
  {
    $limit: 5
  }
]);
Key Differences:
Aspect SQL MongoDB
Syntax Declarative SQL statements JSON-based methods/pipelines
Query Structure Single statement Pipeline of stages
JOINs Native and optimized $lookup (less optimized)
Aggregation GROUP BY with functions $group stage with operators
Learning Curve Familiar to most developers Requires learning new syntax
⚠️ Performance Note:

SQL databases are highly optimized for JOIN operations after decades of development. MongoDB's $lookup is less mature and can be slower. This is why MongoDB encourages embedding data when possible to avoid JOINs entirely.

πŸ’³ Transactions & ACID

Understanding transaction support and ACID compliance in both databases.

Q7 Hard Google Amazon
Explain transaction contention in MongoDB vs SQL. How do write conflicts and retries differ?

βœ“ Complete Answer:

Transaction Contention Overview:

When multiple transactions try to modify the same data simultaneously, contention occurs. How databases handle this differs significantly.

Aspect SQL Databases MongoDB
Locking Mechanism Row-level, table-level, or page-level locks Document-level locking (WiredTiger)
Concurrency Control 2PL (Two-Phase Locking) or MVCC Optimistic concurrency (write conflicts)
Conflict Detection Lock waits or deadlock detection WriteConflict exceptions
Retry Logic Application handles or automatic Application must implement retries
Performance Impact Lock contention can cause waits Write conflicts abort and retry
SQL Transaction Contention:
-- PostgreSQL Example: Lock Contention
-- Transaction 1
BEGIN;
SELECT * FROM accounts WHERE id = 1 FOR UPDATE;  -- Locks row
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
-- ... processing ...
COMMIT;

-- Transaction 2 (concurrent)
BEGIN;
SELECT * FROM accounts WHERE id = 1 FOR UPDATE;  -- WAITS for lock
-- This transaction BLOCKS until Transaction 1 commits
UPDATE accounts SET balance = balance + 50 WHERE id = 1;
COMMIT;

-- Result: Transaction 2 waits (blocks) until Transaction 1 releases lock
-- No retry needed, but performance degrades with high contention
SQL Lock Behavior
  • Pessimistic Locking: Locks acquired early, held until commit
  • Blocking: Concurrent transactions wait in queue
  • Deadlock Detection: Automatic detection and rollback
  • Lock Timeout: Configurable timeout to prevent infinite waits
MongoDB Transaction Contention:
// MongoDB Example: Write Conflict
// Transaction 1
const session1 = client.startSession();
session1.startTransaction();

await accounts.updateOne(
    { _id: 1 },
    { $inc: { balance: -100 } },
    { session: session1 }
);
// ... processing ...
await session1.commitTransaction();

// Transaction 2 (concurrent)
const session2 = client.startSession();
session2.startTransaction();

try {
    await accounts.updateOne(
        { _id: 1 },
        { $inc: { balance: 50 } },
        { session: session2 }
    );
    await session2.commitTransaction();
} catch (error) {
    if (error.hasOwnProperty('errorLabels') && 
        error.errorLabels.includes('TransientTransactionError')) {
        // WriteConflict - Transaction 2 must RETRY
        console.log('Write conflict detected, retrying...');
        await session2.abortTransaction();
        // Application must implement retry logic
    }
}

// Result: Transaction 2 gets WriteConflict and must retry
// No blocking, but requires retry implementation
MongoDB Write Conflict Behavior
  • Optimistic Concurrency: No locks, conflicts detected at commit
  • Non-Blocking: Failed transaction aborts immediately
  • Write Conflicts: Throw TransientTransactionError
  • Application Retries: Developer must implement retry logic
Retry Pattern Implementation:
Best Practice: MongoDB Retry Logic
async function runTransactionWithRetry(txnFunc, session, maxRetries = 3) {
    for (let i = 0; i < maxRetries; i++) {
        try {
            session.startTransaction();
            await txnFunc(session);  // Execute transaction operations
            await session.commitTransaction();
            console.log('Transaction committed successfully');
            return;  // Success!
        } catch (error) {
            await session.abortTransaction();
            
            // Check if error is transient (write conflict)
            if (error.hasOwnProperty('errorLabels') && 
                error.errorLabels.includes('TransientTransactionError')) {
                
                console.log(`Attempt ${i + 1} failed, retrying...`);
                
                // Exponential backoff
                await new Promise(resolve => 
                    setTimeout(resolve, Math.pow(2, i) * 100)
                );
                
                continue;  // Retry
            } else {
                // Non-transient error, don't retry
                throw error;
            }
        }
    }
    throw new Error('Transaction failed after maximum retries');
}

// Usage
const session = client.startSession();
try {
    await runTransactionWithRetry(async (session) => {
        await accounts.updateOne(
            { name: "Alice" },
            { $inc: { balance: -100 } },
            { session }
        );
        await accounts.updateOne(
            { name: "Bob" },
            { $inc: { balance: 100 } },
            { session }
        );
    }, session);
} finally {
    session.endSession();
}
Performance Comparison:
Scenario SQL (Locking) MongoDB (Optimistic)
Low Contention βœ“ Excellent (minimal waits) βœ“ Excellent (no conflicts)
Medium Contention ⚠️ Good (some blocking) ⚠️ Good (some retries)
High Contention ❌ Degrades (long waits, timeouts) ❌ Degrades (many retries, failures)
Read-Heavy Workload βœ“ Excellent (MVCC allows reads) βœ“ Excellent (no conflicts)
Write-Heavy Workload ⚠️ Lock contention increases ⚠️ Write conflicts increase
Real-World Example: Banking System
Scenario: 1000 concurrent transfers on same account

SQL Approach (PostgreSQL):

  • First transaction acquires lock on account row
  • Remaining 999 transactions wait in queue
  • Executes serially: T1 β†’ T2 β†’ T3 β†’ ... β†’ T1000
  • Predictable but slow under high contention
  • No application retry logic needed

MongoDB Approach:

  • All 1000 transactions attempt concurrently
  • First commit wins, rest get WriteConflict
  • 999 transactions abort and retry (with backoff)
  • Eventually all succeed through retries
  • Requires robust retry implementation
Deadlock Handling:
SQL Deadlock Detection
-- Transaction 1
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;  -- Locks account 1
-- ... processing ...
UPDATE accounts SET balance = balance + 100 WHERE id = 2;  -- Wants account 2
COMMIT;

-- Transaction 2 (concurrent)
BEGIN;
UPDATE accounts SET balance = balance - 50 WHERE id = 2;   -- Locks account 2
-- ... processing ...
UPDATE accounts SET balance = balance + 50 WHERE id = 1;   -- Wants account 1
COMMIT;

-- DEADLOCK! PostgreSQL automatically detects and aborts one transaction
-- Error: deadlock detected
-- DETAIL: Process 1234 waits for ShareLock on transaction 5678;
--         blocked by process 5678.
--         Process 5678 waits for ShareLock on transaction 1234;
--         blocked by process 1234.

SQL automatically detects circular waits and aborts one transaction.

MongoDB Deadlock Prevention
// MongoDB doesn't have traditional deadlocks because:
// 1. No lock acquisition - optimistic concurrency
// 2. Conflicts detected at commit time
// 3. First commit wins, others retry

// However, distributed deadlocks CAN occur across shards
// MongoDB uses timeout-based detection

// Transaction 1
session1.startTransaction();
await accounts.updateOne({ _id: 1 }, { $inc: { balance: -100 } }, { session: session1 });
await accounts.updateOne({ _id: 2 }, { $inc: { balance: 100 } }, { session: session1 });
await session1.commitTransaction();  // One commits successfully

// Transaction 2
session2.startTransaction();
await accounts.updateOne({ _id: 2 }, { $inc: { balance: -50 } }, { session: session2 });
await accounts.updateOne({ _id: 1 }, { $inc: { balance: 50 } }, { session: session2 });
await session2.commitTransaction();  // Gets WriteConflict, must retry

// MongoDB aborts conflicting transaction - no circular wait

MongoDB prevents deadlocks through optimistic concurrency and transaction timeouts.

🎯 Interview Gold:

Key Differences:

  • SQL: Pessimistic locking β†’ transactions wait β†’ no retry needed
  • MongoDB: Optimistic concurrency β†’ conflicts abort β†’ application retries
  • SQL: Automatic deadlock detection and resolution
  • MongoDB: Timeout-based deadlock prevention
  • Choose SQL when: High contention expected, predictable performance critical
  • Choose MongoDB when: Low-medium contention, horizontal scaling needed
⚠️ Production Best Practices:
  • MongoDB: Always implement exponential backoff retry logic
  • MongoDB: Design schemas to minimize multi-document transactions
  • SQL: Use appropriate isolation levels (READ COMMITTED vs SERIALIZABLE)
  • SQL: Index foreign keys to reduce lock escalation
  • Both: Monitor transaction duration and conflict rates
  • Both: Use connection pooling to manage concurrent sessions
Q8 Medium Netflix Uber
How do isolation levels differ between MongoDB and SQL? Explain read phenomena and their prevention.

βœ“ Complete Answer:

Isolation Levels Overview:

Isolation determines how transaction integrity is visible to other concurrent transactions. SQL offers multiple levels, MongoDB has different defaults.

Isolation Level SQL Support MongoDB Support
Read Uncommitted βœ“ Supported ❌ Not supported
Read Committed βœ“ Default (most DBs) βœ“ Default outside transactions
Repeatable Read βœ“ Supported βœ“ Snapshot isolation (in transactions)
Serializable βœ“ Supported βœ“ Snapshot isolation provides similar guarantees
Read Phenomena:
1. Dirty Reads

Definition: Transaction reads uncommitted changes from another transaction

-- SQL Example (Read Uncommitted)
-- Transaction 1
BEGIN TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
UPDATE accounts SET balance = 1000 WHERE id = 1;  -- Not committed yet

-- Transaction 2 (concurrent)
BEGIN TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT balance FROM accounts WHERE id = 1;  -- Sees 1000 (dirty read!)
COMMIT;

-- Transaction 1 rolls back
ROLLBACK;  -- Balance reverts to original value

-- Transaction 2 read incorrect data!
  • SQL: Possible with READ UNCOMMITTED
  • MongoDB: NOT possible (minimum is read committed)
2. Non-Repeatable Reads

Definition: Same query returns different results within a transaction

-- SQL Example (Read Committed)
-- Transaction 1
BEGIN;
SELECT balance FROM accounts WHERE id = 1;  -- Returns 500

-- Transaction 2 (concurrent)
BEGIN;
UPDATE accounts SET balance = 1000 WHERE id = 1;
COMMIT;

-- Transaction 1 continues
SELECT balance FROM accounts WHERE id = 1;  -- Returns 1000 (different!)
COMMIT;

-- Same row read twice, different values!
  • SQL: Prevented by REPEATABLE READ or higher
  • MongoDB: Prevented inside transactions (snapshot isolation)
3. Phantom Reads

Definition: New rows appear in repeated query due to inserts

-- SQL Example
-- Transaction 1
BEGIN;
SELECT COUNT(*) FROM accounts WHERE balance > 1000;  -- Returns 5

-- Transaction 2 (concurrent)
BEGIN;
INSERT INTO accounts (id, balance) VALUES (999, 2000);
COMMIT;

-- Transaction 1 continues
SELECT COUNT(*) FROM accounts WHERE balance > 1000;  -- Returns 6 (phantom!)
COMMIT;

-- New row appeared ("phantom") between reads
  • SQL: Prevented only by SERIALIZABLE
  • MongoDB: Prevented inside transactions (snapshot isolation)
MongoDB Snapshot Isolation:
MongoDB Transaction Behavior
// MongoDB snapshot isolation
const session = client.startSession();
session.startTransaction();

// Read 1: Sees snapshot at transaction start
const result1 = await accounts.find(
    { balance: { $gt: 1000 } },
    { session }
).toArray();
console.log('Count:', result1.length);  // 5 documents

// Concurrent update (different session)
await accounts.insertOne({ _id: 999, balance: 2000 });  // Committed

// Read 2: Still sees SAME snapshot (no phantom reads)
const result2 = await accounts.find(
    { balance: { $gt: 1000 } },
    { session }
).toArray();
console.log('Count:', result2.length);  // Still 5 documents!

await session.commitTransaction();
session.endSession();

// Transaction sees consistent snapshot throughout
// No dirty reads, non-repeatable reads, or phantom reads

MongoDB transactions use snapshot isolation by default - preventing all read phenomena.

πŸ’‘ Key Takeaway:

MongoDB's snapshot isolation in transactions is similar to SQL's SERIALIZABLE, but with better performance characteristics. Outside transactions, MongoDB uses read committed semantics.

πŸ“ˆ Scaling Strategies

How each database handles growth.

Q6 Hard Uber Netflix
Compare horizontal vs vertical scaling in MongoDB and SQL. How does sharding differ from SQL partitioning?

βœ“ Complete Answer:

Scaling Approaches:

Vertical Scaling (Scale Up)

Add more resources to single server (CPU, RAM, Disk)

  • Pros: Simple, no code changes, strong consistency
  • Cons: Hardware limits, expensive, single point of failure
  • SQL: Traditional approach, works well initially
  • MongoDB: Also supported, but not the main scaling strategy
Horizontal Scaling (Scale Out)

Add more servers to distribute load

  • Pros: Nearly unlimited scaling, fault tolerance, cost-effective
  • Cons: Complex, consistency challenges, distributed transactions
  • SQL: Difficult, requires manual sharding or clustering
  • MongoDB: Built-in sharding, designed for this
MongoDB Sharding:
MongoDB Sharding Architecture:

Application
     β”‚
     β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ mongos  β”‚ ← Query router (stateless)
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
     β”‚
     β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
     β–Ό            β–Ό            β–Ό            β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Shard 1 β”‚  β”‚ Shard 2 β”‚  β”‚ Shard 3 β”‚  β”‚ Shard 4 β”‚
β”‚(Replica β”‚  β”‚(Replica β”‚  β”‚(Replica β”‚  β”‚(Replica β”‚
β”‚  Set)   β”‚  β”‚  Set)   β”‚  β”‚  Set)   β”‚  β”‚  Set)   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
 userId      userId       userId       userId
 1-250K      250K-500K    500K-750K    750K-1M

Features:
βœ“ Automatic data distribution
βœ“ Automatic chunk splitting and balancing
βœ“ Transparent to application
βœ“ Add shards on the fly
βœ“ Each shard is a replica set (HA)
SQL Horizontal Scaling:
SQL Horizontal Scaling Options:

1. Read Replicas (Easy)
   Primary ──┬──> Replica 1 (read-only)
             β”œβ”€β”€> Replica 2 (read-only)
             └──> Replica 3 (read-only)
   
   βœ“ Scale reads only
   βœ— Writes still bottlenecked on primary

2. Manual Sharding (Hard)
   Application decides which DB to use
   
   if (userId % 4 == 0) β†’ DB Server 1
   if (userId % 4 == 1) β†’ DB Server 2
   if (userId % 4 == 2) β†’ DB Server 3
   if (userId % 4 == 3) β†’ DB Server 4
   
   βœ“ Scales reads and writes
   βœ— Application manages routing
   βœ— Complex queries across shards
   βœ— Rebalancing requires manual migration

3. Clustering Solutions (PostgreSQL Citus, MySQL Cluster)
   βœ“ More automated
   βœ— Less mature than MongoDB sharding
   βœ— Often limited compared to single-server SQL
Comparison Table:
Feature MongoDB Sharding SQL Horizontal Scaling
Ease of Setup Built-in, configure with commands Manual or third-party solutions
Automatic Balancing Yes, background balancer No, manual rebalancing
Routing mongos routes automatically Application logic required
Cross-Shard Queries Supported (broadcast queries) Complex, often not supported
Transactions Cross-shard since v4.2 Very difficult or impossible
Maturity Core feature, well-tested Varies, often immature
Real-World Example:
Scenario: Social Media App Scaling to 100M Users

MongoDB Approach:

// Enable sharding on database
sh.enableSharding("socialMedia")

// Shard users collection on userId
sh.shardCollection("socialMedia.users", { userId: "hashed" })

// Add more shards as user base grows
sh.addShard("shard5/server13:27017,server14:27017,server15:27017")

// System automatically:
// - Distributes new users evenly
// - Balances chunks across shards
// - Routes queries to correct shards

SQL Approach:

// 1. Decide sharding strategy in application code
function getUserDB(userId) {
  const shardNum = userId % 4;  // 4 database servers
  return dbConnections[shardNum];
}

// 2. Every query must include sharding logic
const db = getUserDB(userId);
const user = await db.query("SELECT * FROM users WHERE id = ?", [userId]);

// 3. Cross-shard queries very complex
// Getting all users? Must query ALL shards and merge results!

// 4. Adding 5th shard = rebalance entire system manually
// Move 20% of users from each shard to new shard
πŸ’‘ Key Takeaway:

MongoDB was designed from day 1 for horizontal scaling via sharding. SQL databases were designed for vertical scaling, with horizontal scaling added as an afterthought through third-party solutions or application-level sharding.

πŸŽ‰ Master Database Comparisons!

Understanding MongoDB vs SQL trade-offs is crucial for system design interviews and architectural decisions. Remember: it's not about which is "better" - it's about which is better FOR YOUR USE CASE.

Key Takeaways:

  • MongoDB excels at flexible schemas and horizontal scaling
  • SQL excels at complex transactions and JOIN operations
  • Both support ACID transactions (MongoDB since v4.0)
  • Schema design differs: normalize in SQL, often denormalize in MongoDB
  • Modern applications often use both (polyglot persistence)