MongoDB Document Modeling
Deciding what belongs in one document, when to reference instead, and the patterns that keep documents bounded.
MongoDB modelling starts from access patterns, not from entities. The question is not "what are the things" but "what is read and written together".
Embedding vs Referencing
Embed when the child data is read with the parent, written with the parent, and bounded in size.
// One read returns everything the order page needs.
{
_id: ObjectId("…"),
status: "paid",
shippingAddress: { line1: "…", city: "…", country: "DE" },
items: [ { sku: "TS-001", qty: 2, priceCents: 4950 } ]
}Reference when the child data is large, unbounded, shared between parents, or accessed independently.
// Comments grow without limit — a separate collection.
{ _id: ObjectId("…"), postId: ObjectId("…"), body: "…", createdAt: ISODate("…") }The decision table:
Duplicating fields deliberately
Documents often duplicate a few fields from a referenced entity so the common query needs one read:
{
_id: ObjectId("…"),
customerId: ObjectId("…"),
customerName: "Acme GmbH", // duplicated for the order list view
totalCents: 19900
}This is a legitimate trade: one fewer lookup on a hot path, in exchange for updating the duplicate when the source changes. Duplicate only fields that change rarely, and record where each duplicate lives so an update path exists.
Useful patterns
Bucketing. Instead of one document per reading, store a bucket per hour or per thousand readings. It cuts document count and index size dramatically for time-series-like data.
{
sensorId: "s-1001",
hour: ISODate("2026-07-31T10:00:00Z"),
count: 3600,
readings: [ { t: 0, v: 21.4 }, { t: 1, v: 21.5 } ]
}Computed values. Store the aggregate you query for — an order total, a comment count — updated
with $inc when children change. Avoids recomputing on every read.
Subset. Embed the most recent or most relevant N children and keep the full set in another collection, so the common view needs one read.
The outlier exception. When most documents are small but a few are enormous, mark the outliers with a flag and handle them separately rather than designing the whole collection around them.
Field names count
Field names are stored in every document. On collections with hundreds of millions of small documents, shortening long names measurably reduces storage and working-set size. Balance that against readability — this matters at scale and is premature optimisation below it.