Filter concepts by levelShowing all levels.

MongoDB · Documents and Collections

Documents and Collections

Embed or reference, dot notation, array shape, and what a collection carries beyond a name

  • Embed vs. referenceread-together and bounded embeds; shared or growing references
  • "a.b" dot notationsame syntax in filters, projections, and $set
  • Scalar vs. document arraysplain values vs. structured, multi-field items
  • Collection ≠ just a namevalidators, indexes, capped/time-series modes attach to it

1.Embedded documents vs. references

Embedding puts related data directly inside a document; referencing stores just an _id and looks the related document up separately. Embed what is read together and bounded; reference what grows independently or is shared broadly.

Key features

  • Embedding nests related data inside the parent document, no join needed
  • Referencing stores an _id and requires a second query (or $lookup) to resolve
  • Embed when data is read together, bounded in size, and owned by one parent
  • Reference when data grows independently, is shared, or has its own lifecycle
  • The choice can be mixed per relationship — not all-embed or all-reference

Embed or reference — the deciding questions

Embed or reference — the deciding questions
QuestionFavors embeddingFavors referencing
Read together?yes, almost alwaysrarely, or only sometimes
Bounded size?yes, small and cappedno, or unbounded
Shared by others?no, belongs to one parentyes, reused across documents
Independent lifecycle?no, dies with the parentyes, updated/deleted on its own
Embed vs. reference

Embed

  • Nested inline, no join
  • Read together, bounded
  • Owned by one parent

Reference

  • Stores an _id, needs a lookup
  • Grows independently or shared
  • Has its own lifecycle
  • Embed
    • Nested inline, no join
    • Read together, bounded
    • Owned by one parent
  • Reference
    • Stores an _id, needs a lookup
    • Grows independently or shared
    • Has its own lifecycle

Command

json
// Embed: { "parent": { "child": { ... } } }
// Reference: { "parent": { "childId": ObjectId("...") } }

Embed data that is read together, bounded and owned by one parent. Reference data that grows independently or is shared across many parents.

2.Nested fields and dot notation

Dot notation ("address.city") reaches into an embedded document or an array element without pulling the whole document apart in application code — it works the same way in queries, projections, and update operators.

Key features

  • "a.b" reaches field b inside embedded document a
  • "a.0.b" reaches field b of the array element at index 0 in array a
  • The same dot-path syntax works in query filters, projections and update operators
  • Querying "a.b": value matches any document with that value at that nested path
  • $set: { "a.b": value } sets only the nested field, siblings untouched

Dot notation across the three places it is used

Dot notation across the three places it is used
WhereSyntaxWhat it does
Query filterdb.c.find({ "address.city": "Delhi" })matches nested field by value
Projectiondb.c.find({}, { "address.city": 1 })returns only that nested field
Update ($set)$set: { "address.city": "Pune" }sets only that nested field
Array element"items.0.sku"reaches a specific index inside an array
Walking a dot path one step at a time

document

the whole record

address

"address."

city

"address.city"

  1. document — the whole record
  2. address — "address."
  3. city — "address.city"

Command

text
field.nestedField          // embedded document field
field.0.nestedField        // array element at index 0, then its field

"a.b" reaches field b nested in a, in queries, projections and $set. $set with a dotted path touches only that field, not its siblings.

3.Arrays of scalars vs. arrays of documents

An array field can hold plain scalars (tags: ["a", "b"]) or embedded documents (lines: [{ sku, qty }]). Scalars suit a simple set of values; documents suit structured items that themselves have multiple fields.

Key features

  • A scalar array holds plain values: strings, numbers, booleans
  • A document array holds embedded documents, each with its own fields
  • Both can be indexed as multikey indexes (indexing, section 10)
  • Querying an array of documents by one field uses dot notation or $elemMatch
  • Array of documents is the natural fit once an item needs more than one field

Choosing the array shape

Choosing the array shape
DataArray shapeExample
Tags, categoriesscalars"tags": ["sci-fi", "classic"]
Order line itemsdocuments"lines": [{ "sku": "A1", "qty": 2 }]
Simple list of IDsscalars (ObjectId)"followerIds": [ObjectId("..."), ...]
Comments with author + textdocuments"comments": [{ "author": "...", "text": "..." }]

Command

json
{ "scalarArray": ["a", "b"], "documentArray": [{ "field": "value" }] }

Scalar arrays hold plain values; document arrays hold structured items with their own fields. Both can be indexed as multikey.

4.Document shape and performance

A document's shape is not just a modeling choice — a large unbounded array slows updates on that document, a deeply nested field is more expensive to index, and a document that must be rewritten often should stay small.

Key features

  • Indexing a deeply nested or array field costs more than indexing a top-level scalar
  • A large, frequently updated document is more expensive to rewrite than a small one
  • An unbounded array that keeps growing makes a document's update cost grow with it
  • A multikey index (on an array field) has different constraints than a single-field index
  • Splitting a fast-growing sub-list into its own collection is a common fix

Shape choices and their performance effect

Shape choices and their performance effect
Shape choiceEffect
Small, bounded embedded arraycheap to update and index
Large or unbounded embedded arrayupdate cost grows with the array; risks the 16 MB cap
Deeply nested field, frequently queriedindex still works, but the path is costlier to maintain
Frequently updated large documenteach write rewrites more data than a small document would

Command

text
// No syntax to run — a design constraint to weigh when choosing document shape, not an API call.

Large or unbounded arrays and deep nesting cost more to update and index. Keep frequently-updated documents small and bounded.

5.Collection-level concerns

A collection is more than a grouping — it can carry its own validators, indexes, and a special storage mode (capped or time-series) chosen when it is created, each shaping how documents inside it are stored or constrained.

Key features

  • A schema validator (section 9) constrains what shape documents in a collection may take
  • Indexes (section 10) speed up queries at the cost of write and storage overhead
  • A capped collection is fixed-size and overwrites its oldest documents once full
  • A time-series collection is optimized for high-volume, timestamped measurements
  • Capped and time-series modes are chosen at creation, not added afterward

Collection-level options

Collection-level options
ConcernWhat it doesChosen
Validatorrejects (or warns on) documents that fail a schemaat creation, or added later
Indexesspeed up specific query patternsat any time
Capped collectionfixed size, overwrites oldest on overflowat creation only
Time-series collectionoptimized storage for timestamped measurementsat creation only

Command

text
db.createCollection(name, { capped, size, validator, timeseries, ... })

A collection can carry validators, indexes, or a fixed storage mode (capped, time-series) — chosen mostly at creation time.

6.Collections as business concepts

A collection is best named and shaped around a business concept an access pattern actually needs — "orders", "events" — not a 1:1 mirror of every class in the application's object model.

Key features

  • A collection groups documents by what is read/written together, not by class taxonomy
  • One class in code does not require one collection — types can share a collection
  • A collection per unrelated business concept keeps queries and indexes focused
  • Mirroring every application class as its own collection often adds joins
  • The right grouping follows access patterns, same as data modeling (section 6)

Class model vs. collection model

Class model vs. collection model
ConcernApplication class modelCollection model
Organizing principleinheritance, code structureaccess pattern, what's queried together
Polymorphismoften one class per subtypeoften one collection, a type field distinguishes
Granularityas fine as the domain modelas coarse as the read/write pattern needs

Command

text
// Ask: what is read/written together, not: what class does this belong to.

Shape a collection around what is read/written together, not around the application's class hierarchy — polymorphic types can share one collection.

Remember

  • Embed data read together, bounded and owned by one parent; reference data that grows independently or is shared.
  • "a.b" reaches a nested field in queries, projections and $set — $set on a dotted path touches only that field.
  • Large or unbounded arrays and deep nesting cost more to update and index — keep hot documents small.
  • Shape a collection around what is read/written together, not around the application's class hierarchy.

Pro tip

  • A capped or time-series collection's storage mode is chosen at creation — plan for it upfront, not after the fact.
  • A polymorphic set of types can share one collection with a discriminating field, instead of one collection each.

Next up

  • CRUD Operations
  • Query Language
  • Data Modeling

Sources

  • Document data model — mongodb.com/docs/manual/core/document/
  • Data model design — mongodb.com/docs/manual/core/data-model-design/
  • Checked 2026-08-20

Spotted a mistake on this page? Tell us.