Entities and invariants
Choose representations and storage boundaries from access patterns, ownership and retention requirements.
THE IDEA
Entities and invariants
Start by naming the entities (users, documents, orders), giving each a stable identity, deciding who owns it and writing down the invariants: conditions that must hold across valid operations, such as "ids are unique", "every document has an existing owner", "a balance never goes below zero". A display name is a poor identifier: names repeat and change.
| id | display name | owner (click to change) |
|---|---|---|
| 1 | Report | |
| 2 | Plan | |
| 3 | Report | |
| 4 | Notes |
An invariant is a condition that must stay true across valid operations: unique ids, an existing owner, non-negative balances. Choose identifiers that are stable and unique, and let the system enforce the invariants rather than hoping every writer does.
Predict first. Is a document's display name necessarily a safe unique identifier?
Chapter context
A data model describes the facts a system owns and the relationships it must preserve. Storage choices should follow how those facts are queried, updated and retained, rather than a blanket preference for one database category.
TRY IT YOURSELF
Part 1. Do it hands-on
Check identifiers and ownership by hand, then write invariant checks and an all-or-nothing transfer.
| id | display name | owner (click to change) |
|---|---|---|
| 1 | Report | |
| 2 | Plan | |
| 3 | Report | |
| 4 | Notes |
An invariant is a condition that must stay true across valid operations: unique ids, an existing owner, non-negative balances. Choose identifiers that are stable and unique, and let the system enforce the invariants rather than hoping every writer does.
- To do: Five documents have display names Report, Plan, Report, Notes, Report. How many documents share a display name with another document?
- To do: How many distinct names are duplicated?
- To do: Four documents have owners u1, u2, u9, u1, but only users u1 and u2 exist. How many documents violate the ownership invariant (owner must exist)?
- To do: Is a document's display name necessarily a safe unique identifier? Type yes or no
Part 2. Do it in code
- find_duplicates(rows, field): the sorted values of `field` that occur in more than one row.
- rows_sharing(rows, field): the ids (row['id']) of every row whose value for `field` is shared with another row, sorted.
- orphans(docs, users): the sorted ids of docs whose owner is not in the set of user ids.
- overdrawn(accounts): the sorted names of accounts with a negative balance (accounts maps name → balance).
- transfer(accounts, src, dst, amount): move money and keep the invariants: amount must be positive, src must have enough balance, both accounts must exist (ValueError otherwise, and the accounts must be left unchanged). The total of all balances never changes.
Stuck, or something not working? You can come back to it any time.
CHECK YOUR UNDERSTANDING
Is a document's display name necessarily a safe unique identifier?
Chapter reference: math, worked example & code
This section belongs to the whole chapter, so it is the same on every lesson in it and may cover a different lesson's topic. The code for the experiment you just ran is inside the experiment itself.
Math and notation
A simple retained-payload estimate is
where w is writes/day, s payload bytes/write, d retained days and r full-copy count. Add indexes, metadata, compaction headroom and backups separately; replication schemes may store more than exactly r payload copies.
Worked example
Two million records per day at 500 bytes each produce one decimal GB/day of raw payload. Thirty days retained across three full copies require 2,000,000×500×30×3=90,000,000,000 bytes, or 90 decimal GB before other storage. Compressibility and index size are separate measured factors.
Reference code
The following example uses the Python standard library and does not call a remote service.
daily,size,days,copies=2_000_000,500,30,3
assert daily*size == 1_000_000_000
retained=daily*size*days*copies
assert retained == 90_000_000_000
assert retained/1e9 == 90
Python examples are provided for study and local execution; this page does not execute Python.
Common mistakes
NoSQL is not a single consistency or query model. Denormalization creates a maintenance responsibility. Payload estimates must not silently stand in for provisioned disk requirements.