NoSQL Database Types
Table of Contents#
- What "NoSQL" Actually Means
- Why NoSQL Exists — The Problem It Was Built to Solve
- Schema-on-Write vs Schema-on-Read
- Key-Value Stores
- Document Databases
- Wide-Column (Column-Family) Databases
- Graph Databases
- The Four Types, Side by Side
- CAP Theorem, Revisited for Each NoSQL Type
- SQL vs NoSQL — The Actual Decision Framework
- Polyglot Persistence — Using Several at Once
- A Worked Example: Choosing a Database for a Real System
- Common Mistakes
- Worked Practice Problems
- Summary and What's Next
What "NoSQL" Actually Means#
NoSQL is a genuinely misleading name, worth clarifying immediately — it doesn't mean "no SQL is ever involved" (some NoSQL databases even support SQL-like query languages). The more accurate expansion, worth knowing: "Not Only SQL" — a broad umbrella term for databases that deliberately step away from the traditional relational (tables, rows, JOINs, fixed schema) model covered in Part 4, in exchange for different tradeoffs.
Diagram
A genuinely important framing worth stating explicitly, up front: there is no single "NoSQL database" — it's four genuinely different data models, each solving a different kind of problem, unified only by the fact that none of them is the traditional relational model. Treating "NoSQL" as one interchangeable category is a common, shallow mistake — a strong interview answer always specifies which kind of NoSQL database fits a given use case, and why.
Why NoSQL Exists — The Problem It Was Built to Solve#
Diagram
A concrete, historically important detail worth knowing: many of today's most influential NoSQL databases trace directly back to two specific, highly-cited papers — Amazon's "Dynamo" paper (2007, describing a highly-available, eventually-consistent key-value store) and Google's "Bigtable" paper (2006, describing a distributed, wide-column store). Citing these by name in an interview is a genuine, strong signal of real depth — Cassandra, DynamoDB, and Riak all directly trace their design lineage to Dynamo; HBase and Bigtable itself trace to the Bigtable paper.
Schema-on-Write vs Schema-on-Read#
A foundational distinction underlying almost every NoSQL vs. SQL tradeoff discussion — worth understanding deeply, not just naming.
Diagram
A strong, balanced interview line: "Schema-on-write trades flexibility for guaranteed consistency, enforced centrally by the database. Schema-on-read trades that guarantee for flexibility — which is genuinely powerful for rapidly evolving data shapes, but it means every piece of application code reading that data has to defensively handle the possibility of missing or differently-shaped fields, since nothing enforces consistency for you."
Key-Value Stores#
The simplest possible NoSQL model: every piece of data is a key mapped to an opaque value — the database doesn't know or care what's inside the value at all.
Diagram
Real-world examples worth knowing: Redis (extremely widely used, in-memory, extremely fast — already referenced throughout this course as the standard caching layer), DynamoDB (AWS's managed, highly-scalable key-value/document hybrid), Memcached (a simpler, pure in-memory caching-focused key-value store).
When this model genuinely fits, worth stating explicitly: anything where you always access data by a single, known key, with no need to query or filter based on the contents of the value — session storage, caching (directly connecting to the caching discussion from the Capacity Planning & Performance series), simple counters, and feature flag lookups are all classic, strong fits.
The real limitation worth naming: you generally can't efficiently ask "give me all values where some internal field equals X" — that requires either scanning everything (slow), or maintaining a completely separate index structure yourself, since the database has no visibility into the value's internal structure at all.
Document Databases#
One level richer than key-value: the value itself is a structured document (commonly JSON), and — critically — the database CAN understand and query based on the document's internal fields.
Diagram
// MongoDB — querying INSIDE a document's structure, something // a pure key-value store fundamentally cannot do db.users.find({ "addresses.city": "NYC" })
Real-world examples worth knowing: MongoDB (the dominant, most widely recognized document database), Couchbase, Amazon DocumentDB (a MongoDB-compatible managed service).
Why document databases became so popular, worth stating explicitly, and directly connecting to schema-on-read: they map extremely naturally onto how modern applications already think about data — a JSON object closely mirrors an application's own in-memory object/struct, avoiding the "object-relational impedance mismatch" (the real, historically significant friction of translating between an application's natural object shapes and a relational database's flat, table-based rows) that SQL/ORM-based applications have always had to manage.
A genuinely important, real limitation worth naming — related to the cross-shard transaction discussion from Part 2: document databases historically offered weaker (or no) support for multi-document ACID transactions, though this has genuinely improved in modern versions of MongoDB specifically. A strong interview answer notes this nuance rather than assuming document databases can never do transactions at all — the honest, current answer is "it depends on the specific database and version."
Wide-Column (Column-Family) Databases#
A genuinely different model from both key-value and document stores — optimized specifically for very high write throughput and very large-scale, distributed data, at real design cost to query flexibility.
Diagram
Real-world examples worth knowing: Cassandra (the most widely cited, based directly on Amazon's Dynamo paper's distribution model combined with Google's Bigtable paper's data model), HBase (built directly on top of HDFS/Hadoop), Google Bigtable (the managed cloud version of the original paper's design), ScyllaDB (a high-performance, Cassandra-compatible reimplementation).
Why this model is specifically optimized for massive write volume, worth stating explicitly: writes are typically append-only and distributed across many nodes by design, without the read-optimized index-maintenance overhead of a traditional relational table (Part 4's discussion of every index slowing down writes) — this is precisely why wide-column stores are the standard choice for extremely high-volume time-series data, IoT sensor data, and activity/event logging at massive scale.
The real limitation worth naming: query flexibility is genuinely constrained — you generally need to know your access patterns (how you'll query the data) up front, and design your row-key/column structure specifically around them, since ad hoc, flexible querying (the kind SQL's JOINs and WHERE clauses make trivial) is deliberately not what these systems are optimized for.
Graph Databases#
Purpose-built for data where the relationships between things are just as important as the things themselves — arguably the most conceptually different NoSQL model from the relational one.
Diagram
Real-world examples worth knowing: Neo4j (the most widely recognized, dedicated graph database), Amazon Neptune (AWS's managed graph database service).
Why relational JOINs genuinely struggle with certain graph-shaped questions, worth stating explicitly with a concrete example: a question like "find all of Alice's friends-of-friends, up to 5 degrees of separation" requires a relational query to perform 5 sequential, expensive JOINs against a self-referencing table — and the cost grows dramatically with each additional degree. A graph database traverses relationships DIRECTLY, following actual stored connections, making even very deep traversals (many degrees of separation) genuinely fast, because the relationships themselves are first-class, directly-stored data — not something reconstructed fresh via a JOIN on every single query.
Classic, real-world use cases worth citing: social networks (exactly the friends-of-friends example above), fraud detection (finding suspicious webs of connected accounts/transactions), and recommendation engines ("people who bought X also bought Y, and people similar to THEM bought Z").
The Four Types, Side by Side#
| Key-Value | Document | Wide-Column | Graph | |
|---|---|---|---|---|
| Core unit | An opaque key -> value pair | A structured document (JSON-like) | A row with flexible columns | Nodes + relationships |
| Can query by internal field? | No | Yes | Limited, access-pattern-dependent | Yes, especially relationship traversal |
| Best for | Caching, sessions, simple lookups | Flexible, evolving application data | Massive write volume, time-series | Highly connected, relationship-heavy data |
| Real examples | Redis, DynamoDB, Memcached | MongoDB, Couchbase | Cassandra, HBase, Bigtable | Neo4j, Amazon Neptune |
| Weakest at | Anything needing to query by content | Historically, multi-document transactions | Ad hoc, flexible querying | Not a general-purpose fit for tabular/transactional data |
CAP Theorem, Revisited for Each NoSQL Type#
Directly extending the CAP theorem discussion from the Reliability & Architecture Patterns series — genuinely useful to map real, named databases onto the CP/AP framework already established there.
Diagram
Why this connects so directly, worth stating explicitly, and it's a genuinely strong, integrative interview answer: many NoSQL databases explicitly, deliberately choose a specific point on the CAP spectrum as a core design decision, rather than treating it as an afterthought — Cassandra was built directly on Amazon's Dynamo paper's philosophy, which explicitly prioritizes Availability, using the exact quorum-based tunable consistency (W + R > N) already covered in that earlier tutorial to let operators dial the tradeoff per-query.
SQL vs NoSQL — The Actual Decision Framework#
A genuinely important, senior-level closing framework — the honest answer is never "NoSQL is better" or "SQL is better" in the abstract.
Diagram
A strong, senior-level interview line: "I don't start from 'SQL vs NoSQL' as the question — I start from the actual access patterns: how is this data queried, how often does it change shape, what consistency guarantees does it genuinely need, and what's the expected scale. The database model is a consequence of those answers, not a starting assumption."
Polyglot Persistence — Using Several at Once#
A genuinely important, real-world practice worth knowing by name — most non-trivial real systems don't use just ONE database technology for everything.
Diagram
Why this is worth naming explicitly as its own practice, not just "using multiple databases": each database is deliberately chosen for the SPECIFIC job it's genuinely best suited for, rather than forcing one single technology to handle every kind of data access pattern a real application actually has — directly connecting to the "right tool for the job" theme already established in the Terraform-vs-Ansible discussion in the Automation, CI/CD & GitOps series.
A Worked Example: Choosing a Database for a Real System#
A complete, realistic scenario tying the whole decision framework together.
Scenario: designing the backend for a ride-sharing app, needing to handle: (1) core trip/payment records requiring strong consistency, (2) real-time driver location updates at extremely high write volume, (3) a "find nearby drivers" and "suggest similar riders" recommendation feature.
Diagram
This worked example demonstrates the genuinely strong, senior-level answer pattern: rather than picking one database for the entire application, the right answer decomposes the system by ACTUAL access pattern and consistency requirement, choosing the specific data model that fits each distinct piece — exactly the polyglot persistence practice just covered.
Common Mistakes#
| Mistake | Why It's Wrong | Fix |
|---|---|---|
| Treating "NoSQL" as one interchangeable category | Key-value, document, wide-column, and graph solve genuinely different problems with different tradeoffs | Always specify which specific NoSQL model fits a given use case, and why |
| Choosing a document database purely because "it's more flexible," with no real schema-evolution need | Loses the database-enforced consistency guarantees of schema-on-write for no actual corresponding benefit | Choose schema-on-read specifically when the data's shape genuinely, frequently changes — not by default |
| Assuming a wide-column store supports flexible, ad hoc querying like SQL does | These systems are optimized for known, designed-around access patterns, not arbitrary querying | Design the row-key/column structure around the actual, real query patterns up front |
| Using a relational database to model a deeply, heavily interconnected relationship graph (e.g. "friends of friends of friends") | Requires many expensive, sequential JOINs that grow dramatically slower with each additional degree of separation | Use a graph database when relationship traversal, not tabular lookups, is the dominant query pattern |
| Forcing one single database technology to handle every kind of data access pattern in a large system | No single database model is optimal for every job — caching, transactional data, and event logging all have genuinely different needs | Adopt polyglot persistence — choose the right specialized tool per specific job |
| Assuming NoSQL always means "no transactions" or "no consistency" | Many modern NoSQL databases (and specific configurations) offer strong consistency options — this is a deliberate, tunable choice, not an inherent limitation of the entire category | Check the specific database's actual current capabilities and configuration, not outdated general assumptions |
Worked Practice Problems#
Problem 1: A team is building a social network's "friend suggestions" feature ("people you may know," based on mutual connections up to 3 degrees away) currently implemented as a relational database with a self-referencing friendships table, requiring 3 sequential JOINs per query. As the user base grows, this query has become the single slowest, most resource-intensive part of the entire application. What would you recommend, and why?
Answer: Migrate this specific feature to a graph database (like Neo4j) — the relational model's 3 sequential JOINs to traverse "friends of friends of friends" grows dramatically more expensive with each additional degree and with a larger dataset, exactly the weakness relational databases have with deeply connected data. A graph database stores relationships as first-class, directly-traversable data, making even multi-degree traversals like this fundamentally faster by design — this is precisely the "relationships as the primary query pattern" scenario a graph database is purpose-built for, and it's a great, concrete example of polyglot persistence: keep the rest of the application's transactional data (user accounts, posts) in the existing relational database, and use a graph database specifically for this one relationship-heavy feature.
Problem 2: A team chooses MongoDB (a document database) for a new e-commerce order-processing system specifically because "it's more flexible than SQL," without carefully considering their actual requirements. Six months later, they're struggling with data integrity issues — orders occasionally end up in an inconsistent state (payment recorded but inventory not decremented, or vice versa) during concurrent processing. What was likely under-considered in the original decision, and what would you evaluate?
Answer: Order processing genuinely needs strong, multi-document atomic transaction guarantees — updating an order's payment status and decrementing inventory together need to succeed or fail as one indivisible unit, exactly the Atomicity guarantee from ACID (Part 3/4). If they chose an older MongoDB version, or didn't specifically evaluate and correctly configure its multi-document transaction support, they'd get exactly this class of consistency bug. This is a case where the original decision likely optimized for "flexibility" (a genuine strength of document databases) without weighing it against the actual, specific consistency requirements this particular workload needed — a relational database, with its natively strong ACID guarantees (Part 3/4), might have been the better fit for this specific piece, even if other parts of the same application genuinely do benefit from document flexibility.
Problem 3: A monitoring system needs to ingest 500,000 sensor readings per second from IoT devices, with the only query pattern being "give me all readings for device X between time A and time B." What database type would you recommend, and why would a traditional relational database likely struggle here?
Answer: A wide-column store (like Cassandra) — the extremely high, sustained write volume is exactly what this model is optimized for (append-heavy, distributed writes with minimal per-write index-maintenance overhead), and the known, simple, consistent access pattern (device ID + time range) maps naturally onto a well-designed row-key structure (e.g., partitioned by device ID, clustered by timestamp) without needing the flexible, ad hoc querying a relational database's JOINs and indexes are built for. A traditional relational database would likely struggle specifically because every additional index needed to make reads fast (Part 4) directly slows down writes — and at 500,000 writes/second, that write-side cost compounds into a genuine, severe bottleneck that a write-optimized wide-column store is specifically designed to avoid.
Summary and What's Next#
- "NoSQL" is a misleading umbrella term ("Not Only SQL") covering four genuinely different data models — key-value, document, wide-column, and graph — each with its own distinct strengths, weaknesses, and ideal use cases.
- Schema-on-write (traditional SQL) enforces structure centrally, at the cost of painful schema changes later; schema-on-read (common in document databases) trades that guarantee for real flexibility, shifting the consistency burden to application code.
- Key-value stores (Redis, DynamoDB) excel at simple, known-key lookups like caching and sessions, but can't query by content. Document databases (MongoDB) map naturally onto application objects and support flexible, evolving schemas. Wide-column stores (Cassandra) are purpose-built for massive write throughput with known access patterns. Graph databases (Neo4j) make deep relationship traversal fast in a way relational JOINs fundamentally can't scale to.
- Many NoSQL databases make an explicit CAP theorem choice as a core design decision — Cassandra and DynamoDB trace directly to Amazon's Dynamo paper's Availability-favoring philosophy, using the same tunable quorum consistency already covered in the Reliability & Architecture Patterns series.
- The right database choice is never "SQL vs. NoSQL" in the abstract — it follows from actual access patterns, consistency requirements, and scale, decomposed per specific need.
- Polyglot persistence — deliberately using several different, specialized databases within one larger system — is a genuinely common, mature real-world practice, not an anti-pattern.
Continue to Part 6 (06-mysql-in-depth.md) for a focused, hands-on deep dive into MySQL specifically — its storage engines, replication mechanics, and the practical operational commands used to run it day to day.