Data Modeling
Denormalization and Duplication
Copying a name onto an order so reads stay fast — and who is responsible for keeping it true.
Duplication is a tool. You copy a field so the common read does not $lookup. The cost is who updates the copies, or whether they are allowed to go stale. That choice is the design, not an accident.
Snapshot — meant to freeze
- items.unitPrice on the order
- items.name at checkout
- A price change must not rewrite history
- No sync job
Live copy — meant to match source
- user.city duplicated onto every order
- product.rating duplicated onto a card cache
- Rahul moves → every order is wrong until you fan out
- Needs a rule: sync, or accept stale
{
userId: ObjectId("64a1b2c3d4e5f6a7b8c90001"),
items: [
{ productId: ObjectId("…"), name: "Mechanical Keyboard", quantity: 1, unitPrice: 4500 }
],
amount: 4500
}
// Catalogue can go to 4999 tomorrow. This order stays 4500.Copy when the field is read far more than it changes, and either it is a snapshot or you have an update path (same service updates product title and $updateMany on a cache collection — rare, and easy to get wrong). Do not copy a field you will $lookup anyway. Do not copy a field that changes hourly unless you have a cache with TTL.
Interview question
When is denormalization in MongoDB a good idea?
When it removes a join from the hot read and I can say whether the copy is a snapshot or live. Line-item price and name are snapshots. Copying a user's city onto every order is a live copy — stale unless something updates it. If every write has to fan out to many collections, I copied too much.