NoSQL Interview Questions — Hot Partition Took Down Payment
One node's CPU hit 99% due to a hot partition, slowing payments from 20ms to 5s.
20+ years shipping production code across the stack, with years spent interviewing engineers. Drawn from code that ran under real load.
- ✓Solid grasp of fundamentals
- ✓Comfortable reading code examples
- ✓Basic production concepts
- NoSQL is a family of databases designed for flexible schemas, horizontal scaling, and high throughput
- Four main types: Document (MongoDB), Key-Value (Redis), Wide-Column (Cassandra), Graph (Neo4j)
- CAP trade-off: network partitions are inevitable, so you choose between CP and AP — never all three
- Schema design is query-driven: denormalize heavily, duplicate data intentionally
- Performance insight: a single document fetch can replace 3+ SQL joins, cutting latency from ~50ms to ~12ms
- Production insight: hot partitions in Cassandra or DynamoDB cause 10x latency spikes — always monitor partition key distribution
NoSQL databases are non-relational data stores designed to handle scale, flexibility, and performance demands that traditional SQL databases struggle with — think petabyte-scale user activity logs, real-time session stores, or high-velocity IoT streams. They trade ACID transactions and rigid schemas for horizontal scalability, schema-on-read flexibility, and specialized data models (key-value, document, column-family, graph).
The core problem NoSQL solves is the inability of single-node relational databases to distribute writes and reads across commodity hardware without painful sharding logic or performance cliffs. Companies like Amazon (DynamoDB), Google (Bigtable), and Netflix (Cassandra) built internal NoSQL systems because SQL couldn't keep up with their growth — and those patterns became open-source projects that now power most of the internet's high-traffic backends.
Hot partitions are the single most common production killer in NoSQL systems — they occur when a disproportionate amount of traffic hits one shard or partition, overwhelming that node while others sit idle. This breaks distributed systems because NoSQL's horizontal scaling promise relies on uniform load distribution; a hot partition turns your 100-node cluster into a single-node bottleneck, causing latency spikes, timeouts, and cascading failures that can take down payment processing or real-time dashboards.
The CAP theorem is the fundamental constraint at play here: in a network partition (which is inevitable at scale), you must choose between consistency and availability. NoSQL systems like Cassandra (AP) and MongoDB (CP with primary reads) make different trade-offs, and your hot partition strategy must align with that choice — for example, using consistent hashing with virtual nodes in Cassandra or zone sharding in MongoDB to spread load.
Schema design in NoSQL flips relational normalization on its head: you denormalize aggressively, embedding related data into single documents or rows to avoid expensive joins that kill distributed performance. A payment system might store the full customer profile and order history inside each transaction document, accepting data duplication to guarantee single-digit millisecond reads.
Consistency models range from strong (linearizability, as in etcd or ZooKeeper) to eventual (DynamoDB's default, Cassandra's tunable consistency) — you must choose based on whether your payment system can tolerate stale reads (it usually can't, so you'll use quorum writes and read-repair). Indexing strategies in NoSQL are a tightrope: secondary indexes in Cassandra are notoriously slow for high-cardinality columns, while MongoDB's compound indexes can make or break query performance.
Sharding and replication are the mechanical sympathy layer — consistent hashing distributes data across nodes, replication factors of 3 are standard for fault tolerance, and you must design partition keys that avoid the very hot partitions that took down that payment system.
Imagine a traditional SQL database is like a filing cabinet with labeled folders — every document must fit a specific folder shape. NoSQL is like a giant backpack where you can throw in anything: a photo, a sticky note, a USB drive, a rolled-up poster. No rigid shape required. The trade-off? Finding things takes a different strategy because there's no universal filing rule. That's the core tension you'll be asked about in every NoSQL interview.
| Chrome | Firefox | Safari | Edge |
|---|---|---|---|
| ✓ | ✓ | ✓ | ✓ |
NoSQL databases power some of the most traffic-heavy systems on the planet — think Netflix's viewing history, Twitter's social graph, and Uber's real-time location tracking. Interviewers don't ask about NoSQL to trip you up on syntax. They ask because choosing the wrong database model has sunk real products, and they want to know if you understand the trade-offs well enough to make that call under pressure.
The problem NoSQL solves isn't that SQL is bad. It's that relational databases were designed for a world where data had a known, fixed shape and horizontal scaling wasn't a priority. When your schema changes every sprint, your data is deeply nested, or you need to write to a million users per second across three continents, SQL starts to buckle. NoSQL databases trade some guarantees — like strict ACID transactions — for flexibility and scale.
By the end of this article, you'll be able to explain the four NoSQL data models with real examples, articulate the CAP theorem without reciting a textbook definition, talk confidently about consistency levels and when to sacrifice them, and answer the tricky follow-up questions that expose candidates who just memorized bullet points.
Why Hot Partitions Break Distributed Systems
A NoSQL interview question about hot partitions tests your understanding of how distributed databases actually fail under load. A hot partition occurs when a disproportionate share of requests hits a single node or shard, overwhelming its capacity while other nodes sit idle. This is not a theoretical edge case — it's the direct cause of payment outages, rate-limit failures, and real-time system degradation in production.
The core mechanic is simple: most NoSQL databases (Cassandra, DynamoDB, MongoDB) distribute data using a partition key. When that key is poorly chosen — like a timestamp, a user ID that follows a pattern, or a session token — all writes for the same time window or same user land on one node. The symptom is latency spikes, throttling (429s), or complete node failure. The fix is always key design: use a composite key with a high-cardinality prefix, or add a shard key suffix to spread writes evenly.
You use this knowledge when designing schemas for high-throughput systems — payment processing, event ingestion, leaderboards. The rule: if your partition key can be predicted or has a natural hot spot (e.g., '2025-03-28' for daily logs), you will hit a hot partition. Real systems fail because teams treat NoSQL as 'just a key-value store' without modeling access patterns first.
The CAP Theorem: The Heart of Every NoSQL Architectural Choice
In any distributed system, you can only provide two out of three guarantees: Consistency (every read receives the most recent write), Availability (every request receives a response), and Partition Tolerance (the system continues to operate despite network failures).
Because network partitions are an inevitable reality of distributed hardware, you are almost always choosing between CP (Consistency and Partition Tolerance) and AP (Availability and Partition Tolerance). For example, MongoDB defaults to CP—if the primary node goes down, the system stops writes until a new leader is elected to ensure data isn't lost. In contrast, Cassandra is typically AP—it will keep taking writes even if nodes can't talk to each other, resolving conflicts later using 'Last Write Wins'.
package io.thecodeforge.nosql; import com.mongodb.ReadConcern; import com.mongodb.WriteConcern; import com.mongodb.client.MongoClient; import com.mongodb.client.MongoClients; import com.mongodb.client.MongoDatabase; /** * TheCodeForge — Configuring Consistency Levels in MongoDB * Demonstrating the trade-off between speed and data safety. */ public class MongoConfig { public static void main(String[] args) { MongoClient client = MongoClients.create("mongodb://localhost:27017"); MongoDatabase db = client.getDatabase("forge_records"); // WriteConcern.MAJORITY ensures data is written to a majority of nodes // before acknowledging—prioritizing Consistency over Latency. db.withWriteConcern(WriteConcern.MAJORITY) .withReadConcern(ReadConcern.MAJORITY); System.out.println("Connection established with Strong Consistency settings."); } }
Schema Design: From Normalization to Denormalization
In SQL, we normalize to save space. In NoSQL, storage is cheap, so we denormalize to save time. Instead of joining an Orders table with a Users table at query time, we embed the user's name and address directly into the Order document. This means one 'Get' operation retrieves everything needed for the UI, eliminating the performance bottleneck of complex joins.
But don't over-embed. If you embed everything, document size grows unbounded and can exceed MongoDB's 16MB limit. The rule: embed where you always read the embedded data together. Otherwise, reference and read separately. Query patterns drive the schema — not the data.
{
"order_id": "FORGE-9901",
"timestamp": "2026-03-15T10:00:00Z",
"customer": {
"user_id": "usr_882",
"name": "Senior Engineer",
"tier": "Platinum"
},
"items": [
{ "sku": "BOOK-K8S-01", "price": 45.00, "qty": 1 }
],
"total": 45.00
}Consistency Models: From Strong to Eventual — What You Must Choose
NoSQL systems offer a spectrum of consistency levels, not just 'consistent' vs 'inconsistent'. At one end, strong consistency guarantees that every read returns the latest write — same as ACID. At the other, eventual consistency says that if no new writes happen, all replicas will converge to the same value eventually.
Between these endpoints are tunable models: causal consistency (writes that are causally related are seen in order), monotonic reads (once you read a value, you never see an older one), and read-your-writes (you always see your own latest write). DynamoDB lets you request strongly consistent reads per-query at a higher latency cost. Cassandra offers tunable consistency for both reads and writes.
The trap: candidates often say 'I'll use eventual consistency for everything because it's faster.' That fails when the scenario requires, say, a banking transaction. Interviewers want to hear you reason about the cost of consistency — for strong, you pay latency and availability. For weak, you pay complexity and potential staleness.
package io.thecodeforge.nosql; import software.amazon.awssdk.services.dynamodb.DynamoDbClient; import software.amazon.awssdk.services.dynamodb.model.GetItemRequest; /** * TheCodeForge — Choosing consistency level per query in DynamoDB. * Strongly consistent reads cost more RCUs but show latest data. */ public class DynamoConsistency { public static void main(String[] args) { DynamoDbClient client = DynamoDbClient.create(); // Strongly consistent read for critical data GetItemRequest request = GetItemRequest.builder() .tableName("ForgeAccounts") .key(Map.of("accountId", AttributeValue.fromS("acc_123"))) .consistentRead(true) // 2x RCU cost .build(); var response = client.getItem(request); System.out.println("Account balance: " + response.item().get("balance")); } }
- Strong consistency: The board always shows exactly what's in the freezer — no matter which branch you call.
- Eventual consistency: Branches update their boards when they get around to it — you might see 'Vanilla' even if it just ran out.
- Read-your-writes: You see your own changes immediately, but others might not — like ordering a custom flavor and only the branch you ordered from knows.
- Causal consistency: If I tell you I added sprinkles, you'll see the sprinkles after you see the base cone — order matters.
Indexing Strategies: Making NoSQL Queries Fast Without Losing Writes
NoSQL databases index differently from relational ones. MongoDB supports single-field, compound, multi-key (arrays), text, and geospatial indexes. Cassandra uses a primary key with a partition key and clustering columns — you can only query efficiently by partition key or by clustering columns within a partition. Secondary indexes in Cassandra are notoriously slow for high-cardinality data.
DynamoDB also limits secondary indexes: a Local Secondary Index (LSI) must share the same partition key, while a Global Secondary Index (GSI) can have a different partition key but adds cost and eventually consistent reads.
The key insight: you cannot index 'everything' like in SQL. You must design indexes for your known query patterns. Every extra index slows writes and consumes memory. Interviewers ask this because they've seen production outages caused by runaway secondary indexes in Cassandra.
// TheCodeForge — MongoDB Indexing Examples // Compound index for queries that filter by status and sort by date db.orders.createIndex( { status: 1, createdAt: -1 }, { name: "status_date_idx" } ); // Text index for search db.products.createIndex( { name: "text", description: "text" }, { weights: { name: 10, description: 5 } } ); // Hidden index to test without affecting production db.orders.createIndex( { region: 1 }, { hidden: true } );
Sharding and Replication: How NoSQL Scales Horizontally
Sharding splits data across multiple servers (shards) based on a shard key. MongoDB uses a range-based or hashed shard key. Cassandra distributes data automatically using consistent hashing on the partition key. DynamoDB uses a partition key for internal sharding.
The most common production failure: a skewed shard key causes a hot partition — one node handles 90% of traffic while others idle. Interviewers expect you to know how to choose a good shard key: one that distributes writes evenly and doesn't create hot spots.
Replication provides durability and read scalability. MongoDB uses a replica set with a primary and multiple secondaries. Cassandra uses a peer-to-peer model with configurable replication factor and consistency levels. The replication factor directly affects write throughput and data safety — too low and you lose data on node failure, too high and writes slow down.
// TheCodeForge — Shard Key Selection Examples // Bad: Monotonically increasing key (timestamp) causes writes to go to one shard db.sensors.createIndex({ timestamp: 1 }); db.adminCommand({ shardCollection: "mydb.sensors", key: { timestamp: 1 } }); // Good: Hashed shard key distributes evenly db.adminCommand({ shardCollection: "mydb.sensors", key: { sensorId: "hashed" } }); // DynamoDB: Choose partition key with high cardinality // In this case, customer_id is better than status const tableParams = { TableName: "ForgeOrders", KeySchema: [{ AttributeName: "customer_id", KeyType: "HASH" }], // ... };
- Range-based sharding: Books A–E in building 1, F–J in building 2. Simple but can skew if many readers want building 1.
- Hashed sharding: Books are randomly distributed by hash of title. Even load, but you can't range-query across buildings.
- Hot partition: If all bestsellers end up in building 1, that building is overwhelmed — classic shard key mistake.
- Replication: Copy the entire library to another city for disaster recovery — but updates must sync.
Conflict Resolution: Last Write Wins, CRDTs, and How Real Systems Handle Chaos
In AP systems like Cassandra and DynamoDB, concurrent writes to the same data can cause conflicts. The simplest strategy is 'Last Write Wins' (LWW) — the write with the latest timestamp wins. But LWW has a dangerous flaw: if two clients write simultaneously, one write is silently discarded. In systems where you cannot lose data, you need more sophisticated resolution: application-level conflict resolution (Amazon Shopping Cart pattern), CRDTs (conflict-free replicated data types), or vector clocks.
Cassandra uses LWW by default but allows you to provide a custom conflict resolution class. DynamoDB's 'conditional writes' let you reject overwrites based on a condition. Riak (now deprecated) used vector clocks. Interviewers love to ask: 'How would you implement a shopping cart that doesn't lose items?' The answer isn't LWW — you need to merge sets (a CRDT).
package io.thecodeforge.nosql; import java.util.HashSet; import java.util.Set; /** * TheCodeForge — CRDT-inspired set merge for shopping cart. * Demonstrates conflict-free merge without data loss. */ public class ConflictResolution { public static class Cart { private final Set<String> items = new HashSet<>(); public Cart add(String item) { items.add(item); return this; } public Cart merge(Cart other) { Set<String> merged = new HashSet<>(this.items); merged.addAll(other.items); Cart result = new Cart(); result.items.addAll(merged); return result; } public Set<String> getItems() { return items; } } public static void main(String[] args) { Cart client1 = new Cart().add("shirt").add("shoes"); Cart client2 = new Cart().add("shirt").add("hat"); Cart merged = client1.merge(client2); System.out.println("Merged cart: " + merged.getItems()); // Output: [shirt, shoes, hat] — no items lost } }
Read Repair: Why Your Query Might Rewrite Data Mid-Flight
Most engineers think stale reads are just a latency problem. They're wrong. A stale read in a leaderless database like Cassandra or DynamoDB can silently corrupt an entire report pipeline. The real fix isn't stronger consistency — it's read repair.
When you query a quorum of replicas, the read coordinator compares versions from each node. If one replica lags behind, the coordinator fetches the latest version and pushes it to the outdated node before returning the result to you. This happens on every read if you use read repair chance > 0. That's the why: you get eventual consistency without waiting for a background anti-entropy process to run minutes later.
The trap is thinking read repair is free. It doubles write load during reads. In hot partitions, you'll burn CPU on repair traffic instead of serving requests. The trick is to set read repair chance to 0.5 for write-heavy workloads, then run a periodic full repair during low traffic. You don't repair every read — you gamble half the time and survive.
// io.thecodeforge — interview tutorial // Simulating read repair overhead in Cassandra-like system import random class Replica: def __init__(self, version, data): self.version = version self.data = data read_repair_chance = 0.5 quorum_nodes = 3 stale_reads = 0 repair_triggers = 0 for query in range(1000): versions = [random.randint(1,100) for _ in range(quorum_nodes)] latest = max(versions) staleness = sum(1 for v in versions if v < latest) if staleness > 0: stale_reads += 1 if random.random() < read_repair_chance: repair_triggers += 1 print(f"Stale reads: {stale_reads}") print(f"Read repairs triggered: {repair_triggers}")
Anti-Entropy: The Background Job That Saves Your Cluster From Rot
Distributed databases promise eventual consistency, but without active repair, that promise breaks. Nodes diverge: network partitions heal leaving stale replicas, compaction drops tombstones prematurely, and clock skew mangles vector clocks. Anti-entropy is the background process that detects and fixes these inconsistencies before they become silent data corruption.
Unlike gossip-based failure detection, anti-entropy compares replica contents directly. In Dynamo-style systems, each node runs a Merkle tree comparison against its peers. A node splits its key range into segments, hashes each segment, and transmits only the root hash. The peer replies with the hash for any mismatched subtree, drilling down until the exact differing keys are identified. The repair is surgical: only the stale rows are rewritten, not the entire partition.
This job must run continuously but politely. Aggressive anti-entropy floods the network and starves user queries. Production configurations throttle repair traffic — e.g., limit concurrent tree exchanges per node or schedule repairs during off-peak windows. Cassandra's nodetool repair defaults to incremental mode, repairing only the data that changed since the last run. Neglecting anti-entropy is the fastest path to unrecoverable cluster rot.
import hashlib from collections import defaultdict def build_merkle_tree(keys_values: dict, segment_size: int = 100): # Segment key range and hash each segment sorted_keys = sorted(keys_values.keys()) segments = [sorted_keys[i:i+segment_size] for i in range(0, len(sorted_keys), segment_size)] tree = defaultdict(dict) for level, segment in enumerate(segments): hash_input = ''.join(str(k) for k in segment).encode() tree[level][segment[0]] = hashlib.sha256(hash_input).hexdigest() return tree def anti_entropy_repair(local_tree, remote_tree): differing_segments = [] for level in local_tree: for segment_start, hash_val in local_tree[level].items(): if remote_tree[level].get(segment_start) != hash_val: differing_segments.append(segment_start) return differing_segments # Example usage local = {'a': 'val1', 'b': 'val2', 'c': 'val3'} remote = {'a': 'val1', 'b': 'valX', 'c': 'val3'} print(anti_entropy_repair(build_merkle_tree(local), build_merkle_tree(remote)))
nodetool repair -pr (Cassandra) or scheduled repair windows.NoSQL Categories Deep-Dive: Document, Key-Value, Column, Graph
NoSQL databases are broadly categorized into four types: document, key-value, column-family, and graph. Each category is optimized for different data models and access patterns.
Document Stores (e.g., MongoDB, Couchbase) store data as JSON-like documents. They support nested structures and rich queries, making them ideal for content management, catalogs, and user profiles. Example: storing a user with embedded addresses and orders.
Key-Value Stores (e.g., Redis, DynamoDB) are the simplest, storing data as key-value pairs. They excel at high-speed lookups and caching. Example: session storage where session ID is the key and user data is the value.
Column-Family Stores (e.g., Cassandra, HBase) store data in columns grouped by row key. They are designed for write-heavy workloads and time-series data. Example: storing sensor readings where row key is device ID and columns are timestamps.
Graph Databases (e.g., Neo4j, Amazon Neptune) represent data as nodes and edges, optimized for traversing relationships. Example: social network where users are nodes and friendships are edges.
Choosing the right category depends on your data model, query patterns, and consistency requirements. For instance, a payment system might use a document store for transaction records and a key-value store for real-time balance caching.
# Document store (MongoDB) - user document user = { "_id": "user123", "name": "Alice", "addresses": [ {"type": "home", "city": "NYC"} ], "orders": [ {"order_id": "ord1", "amount": 100} ] } # Key-value store (Redis) - session cache SET session:user123 '{"name": "Alice", "cart": ["item1"]}' # Column-family store (Cassandra) - time-series INSERT INTO sensor_data (device_id, time, temperature) VALUES ('sensor1', '2025-01-01T00:00:00Z', 22.5); # Graph database (Neo4j) - social graph CREATE (alice:User {name: 'Alice'})-[:FRIENDS_WITH]->(bob:User {name: 'Bob'})
MongoDB Aggregation Pipeline: $lookup, $unwind, $group Patterns
MongoDB's aggregation pipeline is a powerful framework for data processing. It consists of stages that transform documents as they pass through. Key stages include $lookup (join), $unwind (deconstruct arrays), and $group (aggregate).
$lookup performs a left outer join with another collection. Example: joining orders with customers to get customer details for each order.
$unwind deconstructs an array field, creating a document for each element. This is often used after $lookup when the joined field is an array.
$group groups documents by a specified expression and applies accumulator expressions like $sum, $avg, $max.
Common pattern: $lookup -> $unwind -> $group. For instance, to compute total sales per customer: first $lookup orders from order collection, $unwind the orders array, then $group by customer ID summing order amounts.
Another pattern: $match early to filter documents, reducing data flow. Use $project to reshape documents. $sort and $limit for pagination.
Performance tips: ensure indexes on fields used in $match and $lookup. Avoid $unwind on large arrays. Use $lookup with pipeline for more control.
Example: Find top 5 customers by total order value.
``javascript db.customers.aggregate([ { $lookup: { from: "orders", localField: "_id", foreignField: "customer_id", as: "orders" } }, { $unwind: "$orders" }, { $group: { _id: "$_id", total: { $sum: "$orders.amount" } } }, { $sort: { total: -1 } }, { $limit: 5 } ]) ``
// Aggregation pipeline: top 5 customers by total order value db.customers.aggregate([ { $lookup: { from: "orders", localField: "_id", foreignField: "customer_id", as: "orders" }}, { $unwind: "$orders" }, { $group: { _id: "$_id", total: { $sum: "$orders.amount" } }}, { $sort: { total: -1 }}, { $limit: 5 } ])
explain(). For real-time aggregations, consider materialized views or pre-aggregated collections to avoid heavy pipelines on every request.DynamoDB Design: Single-Table Design, GSI, LSI, Partition Skew
DynamoDB is a fully managed key-value and document database. Effective design is crucial for performance and cost. Key concepts: single-table design, global secondary indexes (GSI), local secondary indexes (LSI), and partition skew.
Single-Table Design advocates using one table for multiple entity types, leveraging sort keys and indexes to model relationships. This reduces the number of tables and enables efficient queries. Example: storing users and orders in one table with partition key = user_id, sort key = entity_type#id (e.g., "USER#user123" or "ORDER#ord456").
GSI allows querying on non-primary key attributes. They have their own partition and sort keys. Use GSIs for access patterns not covered by the base table. Example: query orders by status using a GSI with status as partition key.
LSI is an index that shares the same partition key as the base table but a different sort key. It must be created at table creation. Useful for alternative sort orders within a partition.
Partition Skew (hot partition) occurs when one partition key receives disproportionate traffic, causing throttling. Mitigations: use composite keys, add random suffixes, or use write sharding. Example: for a leaderboard, use partition key = game#date to distribute writes.
Best practices: model access patterns first, then design tables. Use GSIs sparingly (cost). Monitor CloudWatch metrics for throttling. Use DynamoDB Accelerator (DAX) for read-heavy workloads.
- Partition key: PK (e.g., user#123)
- Sort key: SK (e.g., order#456)
- Attributes: data, type, status, timestamp
- GSI: on status for querying active orders.
import boto3 dynamodb = boto3.resource('dynamodb') table = dynamodb.Table('MyTable') # Single-table design: user and order # PK = 'USER#user123', SK = 'PROFILE' # PK = 'USER#user123', SK = 'ORDER#ord456' # Query all orders for a user response = table.query( KeyConditionExpression='PK = :pk AND begins_with(SK, :prefix)', ExpressionAttributeValues={ ':pk': 'USER#user123', ':prefix': 'ORDER#' } ) # GSI query: orders by status gsi_response = table.query( IndexName='StatusIndex', KeyConditionExpression='#status = :status', ExpressionAttributeNames={'#status': 'status'}, ExpressionAttributeValues={':status': 'ACTIVE'} )
Hot Partition Took Down Payment Processing
- Test partition key distribution with realistic traffic patterns — not just uniform assumptions.
- Always monitor per-node request rates, not just cluster averages.
- Pre-split frequently accessed data to avoid logical hot spots.
explain(). Look for COLLSCAN. Add compound indexes matching your query patterns. Verify working set fits in RAM — if mongostat shows >80% page faults, scale memory or shard.Use the mental model: 'When I choose [C|A|P], I lose [the other option]. My trade-off is...'Reference a concrete database: 'Cassandra is AP by default, MongoDB is CP by default.'List the question back: 'So we need to store user profiles, but also query by email and last login? That suggests a document store with secondary indexes.'Admit the trade-off: 'I'd start with MongoDB, but if we need ultra-low latency writes at scale, Cassandra might be better.'Mention DynamoDB's approach: conditional writes and conflict-free replicated data types (CRDTs) for counters and sets.Show you understand the cost: 'Eventual consistency gives you availability during partitions, but you need application-level conflict resolution or accept stale reads.'| NoSQL Type | Best Use Case | Lead Players |
|---|---|---|
| Document Store | Content Management, E-commerce, User Profiles | MongoDB, CouchDB |
| Key-Value Store | Caching, Session Management, Pub/Sub | Redis, Memcached |
| Wide-Column | IoT Telemetry, Time-Series, Large-Scale Analytics | Cassandra, ScyllaDB, Hbase |
| Graph Database | Social Graphs, Fraud Detection, Recommendation Engines | Neo4j, Amazon Neptune |
| File | Command / Code | Purpose |
|---|---|---|
| io | /** | The CAP Theorem |
| io | { | Schema Design |
| io | /** | Consistency Models: From Strong to Eventual |
| io | db.orders.createIndex( | Indexing Strategies |
| io | db.sensors.createIndex({ timestamp: 1 }); | Sharding and Replication |
| io | /** | Conflict Resolution |
| ReadRepairCost.py | class Replica: | Read Repair |
| merkle_compare.py | from collections import defaultdict | Anti-Entropy |
| categories_example.py | user = { | NoSQL Categories Deep-Dive |
| aggregation.js | db.customers.aggregate([ | MongoDB Aggregation Pipeline |
| dynamodb_design.py | dynamodb = boto3.resource('dynamodb') | DynamoDB Design |
Key takeaways
Interview Questions on This Topic
Explain the 'Last Write Wins' (LWW) conflict resolution strategy. What are its risks in a globally distributed database?
How does a Bloom Filter help improve read performance in databases like Cassandra?
Describe a scenario where you would intentionally choose Eventual Consistency over Strong Consistency.
What is the difference between a Global Secondary Index and a Local Secondary Index in DynamoDB?
If you were building a real-time 'Trending Topics' feature for Twitter, which NoSQL type would you use and why?
Frequently Asked Questions
Choose SQL when your data schema is stable and you need complex, multi-row transactions with high data integrity. If your queries involve joining many different tables in unpredictable ways, SQL's relational model is far superior.
Split-brain occurs when a network partition divides a cluster into two groups, both of which believe they are the authoritative 'leader'. Without a quorum/consensus algorithm (like Raft or Paxos), both sides might accept different writes, leading to data corruption.
Sharding is the process of breaking up a large dataset into smaller chunks (shards) and distributing them across multiple servers. Each shard acts as an independent database, allowing the system to handle massive loads by spreading the work. The shard key determines which shard stores each piece of data.
Yes, modern NoSQL databases like MongoDB 4.0+ and DynamoDB support ACID transactions, but with a cost: they require consensus across nodes, which increases latency. The real trade-off is not 'ACID vs NoSQL' but 'how much latency can you tolerate for transactional guarantees?' In practice, many applications use eventual consistency for 99% of operations and transactions only for critical financial writes.
A hot partition is when one shard receives disproportionately high traffic because the partition key distribution is uneven. Fixes include: using a hashed shard key, adding a random suffix to the partition key, or partitioning by a different attribute. In Cassandra, use 'nodetool cfstats' to identify hot partitions. In DynamoDB, use CloudWatch metrics 'ThrottledWriteEvents'.
NoSQL schemas are flexible, but applications still expect certain fields. Strategies include: (1) use optional fields with default values in code, (2) run background migration jobs to rewrite old documents, (3) version your documents with a schema_version field and handle multiple versions in your application code. MongoDB's $merge pipeline can transform data during aggregation.
20+ years shipping production code across the stack, with years spent interviewing engineers. Drawn from code that ran under real load.
That's Database Interview. Mark it forged?
8 min read · try the examples if you haven't