Guide

Choosing a data model

Documents win on flexible schemas, locality, and matching app objects; tables win on joins and shared links.

When documents fit

Use documents for a tree of one-to-many lists that you load whole. Splitting such a tree into many tables (shredding) leads to clumsy schemas and code. But you can't point straight at a nested item; you say "item 3 of order 88". If others must point at nested items, use tables with IDs. A list the user reorders is easy in a JSON array and awkward in tables.

Schema-on-read and schema-on-write

Most document stores don't enforce a schema, but reading code still expects certain fields. That is an implicit schema: schema-on-read, like dynamic typing. Relational databases check a declared schema on every write: schema-on-write, like static typing. Schema-on-read suits many kinds of records, or shapes set by outside systems.

Changing the shape of data

Say you split full name into first and last name.

  • Schema-on-read: write the new fields, and readers handle old records forever.
  • Schema-on-write: run a migration. Adding a column with a default is fast in most databases. Updating every row to fill it is slow.

A middle path: add the column as empty and fill it in when you read.

Data locality

A document is stored in one piece, so reading all of it is fast. But the database usually loads the whole document even for one field, and rewrites it on every change, so keep documents small. Locality is not only for documents: Spanner can nest child rows in a parent table, and Bigtable-style stores use column families.

Document queries and convergence

Some document stores only fetch by key; others have full query languages. MongoDB's aggregation pipeline filters, groups, and joins (with $lookup), about like a subset of SQL in JSON form. Relational databases added JSON; document databases added joins.

Remember

  • Trees loaded whole: documents. Shared or pointed-at items: tables.
  • "Schemaless" still has a schema, checked by readers.
  • Adding a column is fast; rewriting every row is slow.
  • Locality helps only when you read most of the document.