100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
MongoDB

Data Modeling Patterns

A tour of named MongoDB schema design patterns — attribute, bucket, computed, subset, and extended reference — and the problems each one solves.

Schema DesignAdvanced10 min readJul 10, 2026
Analogies

Why Named Patterns Matter

Beyond the basic embed-vs-reference decision, MongoDB's engineering team has cataloged recurring schema shapes, called patterns, that solve specific recurring problems: too many similar fields cluttering indexes, documents that need to reflect an expensive aggregate cheaply, or a dashboard that only needs a sliver of a large document. Recognizing these patterns saves you from reinventing an ad hoc fix and gives your team a shared vocabulary — saying 'let's use the computed pattern here' communicates the intent and trade-offs far faster than describing the mechanics from scratch each time.

🏏

Cricket analogy: A bowling coach who recognizes a batsman's weakness as a textbook 'in-swinger to a front-foot player' can prescribe a known plan immediately, rather than improvising; named schema patterns work the same way, giving engineers a shared, well-tested playbook.

The Attribute and Subset Patterns

The attribute pattern handles documents with many similar optional fields — say, a product catalog where cameras have 'megapixels' and 'sensorSize' while blenders have 'wattage' and 'jarCapacity.' Instead of dozens of sparse top-level fields (which each need their own index and complicate queries), you store an array of { k: fieldName, v: value } pairs and put a single index on attributes.k and attributes.v, letting you query heterogeneous attributes uniformly. The subset pattern addresses the opposite problem: when a document is large but a view only needs a slice of it (e.g., a product page's info panel doesn't need all 200 reviews), you keep a smaller, frequently-accessed subset embedded, with the full data set living in a separate 'sibling' collection referenced by the same _id convention.

🏏

Cricket analogy: A cricket equipment database uses the attribute pattern because bats have 'willowGrade' and 'weight' while pads have 'sizeRange' and 'material' — storing these as key-value pairs avoids a sparse table with dozens of mostly-empty columns.

The Bucket and Computed Patterns

The bucket pattern groups time-series or event-style data into fixed-interval documents rather than one document per reading — for instance, one document per sensor per hour containing an array of that hour's readings, plus precomputed min/max/avg for the bucket. This drastically reduces the document count (and thus index entries) compared to one document per reading, while keeping documents bounded because each bucket has a natural time-based cap. The computed pattern caches the result of an expensive calculation (like a running total, an average rating, or a leaderboard rank) directly on a document, recalculating it periodically or on write rather than on every read; this shifts CPU cost from a high-frequency read path to a lower-frequency write or batch path, at the cost of the cached value being briefly stale.

🏏

Cricket analogy: A weather station near the ground uses the bucket pattern, storing one document per hour with all the wind-speed readings inside it, rather than a separate document for every single reading, keeping the dataset compact for a rain-delay decision.

javascript
// Attribute pattern: heterogeneous product specs as key-value pairs
db.products.insertOne({
  _id: ObjectId(),
  name: "Mirrorless Camera X200",
  category: "camera",
  attributes: [
    { k: "megapixels", v: 24 },
    { k: "sensorSize", v: "APS-C" },
    { k: "iso", v: [100, 51200] }
  ]
});
db.products.createIndex({ "attributes.k": 1, "attributes.v": 1 });

// Bucket pattern: one document per sensor per hour
db.sensorReadings.insertOne({
  sensorId: "temp-04",
  bucketStart: ISODate("2026-07-10T09:00:00Z"),
  readings: [
    { ts: ISODate("2026-07-10T09:00:12Z"), value: 21.4 },
    { ts: ISODate("2026-07-10T09:00:24Z"), value: 21.5 }
  ],
  count: 2, sum: 42.9, min: 21.4, max: 21.5
});

// Computed pattern: cached aggregate updated on write
db.products.updateOne(
  { _id: productId },
  { $inc: { unitsSold: 1, revenueTotalCents: 4999 } }
);

MongoDB's official 'Building with Patterns' series names roughly a dozen patterns, including attribute, bucket, computed, subset, extended reference, outlier, polymorphic, tree, and approximation. You rarely need all of them in one schema — pick the pattern that matches the specific pain point you're solving.

The computed pattern introduces eventual staleness: a cached average rating or running total can lag the true value between recalculation cycles. Make sure the staleness window is acceptable for the use case (a leaderboard refreshed every few minutes is usually fine; a bank balance is not).

  • Named patterns give teams a shared vocabulary for recurring schema problems, beyond basic embed-vs-reference.
  • The attribute pattern replaces sparse, heterogeneous top-level fields with key-value pairs and a single compound index.
  • The subset pattern keeps a small frequently-used slice embedded while the full data lives in a sibling collection.
  • The bucket pattern groups time-series events into fixed-interval documents, reducing document and index-entry count.
  • The computed pattern caches expensive aggregates on write, trading a bit of staleness for much faster reads.
  • Patterns are tools for specific pain points, not a checklist to apply everywhere.
  • MongoDB's 'Building with Patterns' blog series is the canonical reference for the full pattern catalog.

Practice what you learned

Was this page helpful?

Topics covered

#MongoDB#MongoDBStudyNotes#Database#DataModelingPatterns#Data#Modeling#Patterns#Named#StudyNotes#SkillVeris