Last updated: 2026-09-18

U
Undergraduate level

NoSQL Databases: Four Models Beyond the Table

Relational modelling answers a specific question well: given a domain with unpredictable, ad-hoc queries and a need to keep facts consistent as they're updated, how should data be organised? Normalization's answer — decompose into small tables, join them back together at query time — is a deliberate trade: safety against update anomalies, paid for in JOIN cost at read time. That trade stops looking free once a dataset is sharded across hundreds of machines, because a join across shards means a network round-trip, and a system built to survive a machine or a data centre disappearing mid-request can't always wait for one. The databases usually grouped under "NoSQL" aren't a single alternative to the relational model; they're four different bets about which of a table's guarantees to give up, made by engineers solving that scale problem at Amazon and Google in the mid-2000s.

The CAP Theorem

Eric Brewer's conjecture, later formalized and proved by Seth Gilbert and Nancy Lynch, states that a distributed data store can offer at most two of three properties: Consistency (every read sees the most recent write), Availability (every request gets a response), and Partition tolerance (the system keeps working when network messages between nodes are lost or delayed)1. Partitions happen — a switch fails, a data centre link drops — so partition tolerance isn't really optional for a system spread across many machines; the real choice CAP describes is what happens during a partition: stay available and risk a stale or conflicting read, or refuse to answer until consistency can be guaranteed again. Amazon's Dynamo, one of the first large production systems to make this trade explicit, chose availability — every write succeeds somewhere, and conflicting versions are reconciled later — specifically because a shopping cart that's briefly wrong is a better outcome for the business than a checkout page that's down2. Each of the models below embodies one answer to that same question, at the level of how a single record is stored rather than how the whole cluster is coordinated.

Key-Value and Document Stores

A key-value store is the simplest possible model: an opaque key maps to an opaque value, retrieved whole and never queried by its contents. Redis and DynamoDB both work this way — the store doesn't know or care what's inside the value, so there's no schema to violate:

SET session:8f3a1c '{"user_id": 402, "cart": ["book:119", "book:87"]}'
GET session:8f3a1c

A document store (MongoDB is the familiar example) keeps that key-to-blob shape but makes the blob queryable — it's parsed as structured data (typically JSON), so a query can filter or index on a field inside it. The natural move is to store an entire logical record as one document rather than splitting it across tables. Recall the library's loan example from the companion page: a document store would keep this as a single object instead of three joined tables:

{
  "_id": "loan_5021",
  "member": { "name": "A. Diallo", "email": "a.diallo@example.com" },
  "books": [
    { "isbn": "978-0-441-01359-3", "title": "Dune", "due_date": "2026-10-01" }
  ]
}

Read that back against the companion page's own worked example and the shape is unmistakable: this is the unnormalized table from before First Normal Form, with member nested instead of comma-separated and books an array instead of a text blob. That's not a mistake here — it's the model working as intended. If Diallo's email changes, every loan document mentioning them needs updating individually, the exact multi-copy risk normalization exists to rule out. A document store accepts that risk deliberately, in exchange for retrieving a whole loan — member, books, due dates — in a single lookup with no join at all. That trade is worth making when a record is read far more often than its duplicated fields change, and painful when it isn't.

Column-Family (Wide-Column) Stores

Google's Bigtable, and Cassandra after it, organise data as rows identified by a row key, with columns grouped into families — but unlike a relational table, two rows don't have to populate the same columns at all3. The schema is effectively per-row rather than per-table:

Row keyprofile:nameevent:2026-09-01event:2026-09-15event:2026-09-17
user_402A. Diallologincheckout
user_781login

A relational table with one column per possible event date would be absurd — mostly empty, and unbounded in width as time goes on. A column-family store is built for exactly this shape: sparse, wide, and growing, where the "schema" is really just whatever columns a given row happens to have written. The trade is the mirror image of the document store's: enormous sparse datasets become cheap to store and to scan by row key, at the cost of the query flexibility a fixed, known column set provides — there's no equivalent of "give me every row where profile:signup_date is before X" without already knowing which rows might have that column.

Graph Databases

A relational schema treats a relationship as something to be reconstructed at query time — a foreign key, or for many-to-many, a junction table joined back in. A graph database inverts that: nodes and the edges between them are both stored directly, each carrying their own properties, so a relationship is a first-class stored fact rather than something inferred through a join4. The library's co-authorship case from the companion page — which needed a junction table in a relational schema — looks like this as a property graph instead:

graph LR M[Member: A. Diallo] -- BORROWED --> B1[Book: Dune] B1 -- WRITTEN_BY --> A1[Author: Frank Herbert] B2[Book: The Left Hand of Darkness] -- WRITTEN_BY --> A1 B2 -- WRITTEN_BY --> A2[Author: Ursula K. Le Guin]

Co-authorship (B2 having two WRITTEN_BY edges) needs no separate table here — it's just two edges from the same node, exactly as natural as one. Where a graph model earns its keep is queries that chase relationships several hops deep with a depth that isn't known in advance — "books by any author who has ever co-written with someone Diallo has borrowed from," say — which in a relational schema means a chain of joins whose length has to be decided before the query is written. A graph engine walks the edges directly instead. That power is narrow, though: it's a poor fit for the kind of aggregate, whole-table reporting query a relational or column-family store handles easily, because there's no equivalent of scanning a column efficiently when the data is organised around traversal rather than tabulation.

Choosing a Model

None of the four models above makes the relational model obsolete, and "NoSQL" was never really one thing to switch to — Rick Cattell's contemporary survey of the field groups them as distinct families precisely because each answers a different access pattern, not a single alternative to SQL5. Every one of them is making the same kind of choice the companion page's own closing section describes for denormalization within a relational schema — trading some of Codd's original consistency guarantees for a specific, known access pattern — except here that trade is built into the storage engine itself rather than left as a schema design decision. The practical question is never "which database is better," it's "what does this workload actually do": ad-hoc queries over consistent, structured facts still point at a relational engine; a whole-record read/write pattern points at documents; a huge sparse time series points at wide columns; deep, unpredictable traversal points at a graph. Picking the model to fit the access pattern, rather than the access pattern to fit whichever database is already installed, is the actual skill being exercised.

References


  1. Gilbert, S., & Lynch, N. (2002). Brewer's conjecture and the feasibility of consistent, available, partition-tolerant web services. ACM SIGACT News, 33(2), 51–59. https://doi.org/10.1145/564585.564601

  2. DeCandia, G., Hastorun, D., Jampani, M., Kakulapati, G., Lakshman, A., Pilchin, A., Sivasubramanian, S., Vosshall, P., & Vogels, W. (2007). Dynamo: Amazon's highly available key-value store. ACM SIGOPS Operating Systems Review, 41(6), 205–220. https://doi.org/10.1145/1323293.1294281

  3. Chang, F., Dean, J., Ghemawat, S., Hsieh, W. C., Wallach, D. A., Burrows, M., Chandra, T., Fikes, A., & Gruber, R. E. (2006). Bigtable: A distributed storage system for structured data. In Proceedings of the 7th USENIX Symposium on Operating Systems Design and Implementation (OSDI '06) (pp. 205–218). USENIX Association. https://www.usenix.org/legacy/event/osdi06/tech/chang/chang.pdf

  4. Angles, R., & Gutiérrez, C. (2008). Survey of graph database models. ACM Computing Surveys, 40(1), Article 1. https://doi.org/10.1145/1322432.1322433

  5. Cattell, R. (2010). Scalable SQL and NoSQL data stores. ACM SIGMOD Record, 39(4), 12–27. https://doi.org/10.1145/1978915.1978919