All skills
Skillintermediate

pattern computed

**Pre-calculate and store frequently-accessed computed values.** If you're running the same aggregation on every page load, you're wasting CPU cycles. Store the result in the document and update it on write or via background job—trades write complexity for read speed.

Claude Code Knowledge Pack7/10/2026

Overview

Use Computed Pattern for Expensive Calculations

Pre-calculate and store frequently-accessed computed values. If you're running the same aggregation on every page load, you're wasting CPU cycles. Store the result in the document and update it on write or via background job—trades write complexity for read speed.

Incorrect (calculate on every read):

// Movie with all screenings in separate collection
{ _id: "movie1", title: "The Matrix" }

// Screenings collection - thousands of records
{ movieId: "movie1", date: ISODate("..."), viewers: 344, revenue: 3440 }
{ movieId: "movie1", date: ISODate("..."), viewers: 256, revenue: 2560 }
// ... 10,000 screenings

// Movie page aggregates every time
db.screenings.aggregate([
  { $match: { movieId: "movie1" } },
  { $group: {
    _id: "$movieId",
    totalViewers: { $sum: "$viewers" },
    totalRevenue: { $sum: "$revenue" },
    screeningCount: { $sum: 1 }
  }}
])
// Repeated scans can add substantial read latency and CPU overhead
// 1M page views/day = 1M expensive aggregations

Correct (pre-computed values):

Store computed stats directly in the movie document: stats.totalViewers, stats.totalRevenue, stats.screeningCount, stats.avgViewersPerScreening, and stats.computedAt. The movie page reads a single document with no aggregation needed on the hot path.

Update strategies:

// Strategy 1: Update on write (low write volume)
// When new screening is added
db.screenings.insertOne({
  movieId: "movie1",
  viewers: 400,
  revenue: 4000
})

// Immediately update computed values
db.movies.updateOne(
  { _id: "movie1" },
  {
    $inc: {
      "stats.totalViewers": 400,
      "stats.totalRevenue": 4000,
      "stats.screeningCount": 1
    },
    $set: { "stats.computedAt": new Date() }
  }
)

// Strategy 2: Background job (high write volume)
// Run hourly/daily aggregation job
db.screenings.aggregate([
  { $group: {
    _id: "$movieId",
    totalViewers: { $sum: "$viewers" },
    totalRevenue: { $sum: "$revenue" },
    count: { $sum: 1 }
  }},
  { $merge: {
    into: "movies",
    on: "_id",
    whenMatched: [{
      $set: {
        "stats.totalViewers": "$$new.totalViewers",
        "stats.totalRevenue": "$$new.totalRevenue",
        "stats.screeningCount": "$$new.count",
        "stats.computedAt": "$$NOW"
      }
    }]
  }}
])

Common computed values:

Source DataComputed ValueUpdate Strategy
Order line itemsOrder totalOn write (single doc)
Product reviewsAvg rating, review countBackground job
User activityEngagement scoreBackground job
Transaction historyAccount balanceOn write
Page viewsView count, trending scoreBatched updates

Handling staleness:

Include a computedAt timestamp alongside the stats. Application code compares this timestamp against a freshness threshold (e.g. one hour) and triggers a refresh if the values are stale. Alternatively, surface the timestamp to users (e.g. “1,840,000 viewers — updated 1 hour ago”).

Windowed computations:

// Compute for time windows (rolling 30 days)
{
  _id: "movie1",
  stats: {
    allTime: { viewers: 1840000, revenue: 25880000 },
    last30Days: { viewers: 45000, revenue: 630000 },
    last7Days: { viewers: 12000, revenue: 168000 }
  }
}

// Background job updates rolling windows
db.screenings.aggregate([
  { $match: {
    movieId: "movie1",
    date: { $gte: thirtyDaysAgo }
  }},
  { $group: {
    _id: null,
    viewers: { $sum: "$viewers" },
    revenue: { $sum: "$revenue" }
  }}
])
// Then update movie.stats.last30Days

Consider on-demand materialized views:

When the computed results are best stored in a separate collection rather than embedded in the source documents, MongoDB's on-demand materialized views formalize this approach. An on-demand materialized view is an aggregation pipeline whose output is written to a separate collection using $merge or $out—the same mechanism shown in Strategy 2 above. The difference is conceptual: instead of updating a field on existing documents, you maintain a dedicated read-optimized collection that can be independently indexed. This is especially useful when:

  • The computed data has a different shape or granularity than the source (e.g. monthly summaries from daily records).
  • Multiple consumers need the pre-aggregated data, and a shared collection is cleaner than duplicating fields across documents.
  • You want to index the computed results independently of the source collection.

On-demand materialized views are not automatically refreshed—you control when to re-run the pipeline, which gives you the same staleness trade-offs described above.

When NOT to use this pattern:

  • Rarely accessed calculations: If stat is viewed once/day, compute on demand.
  • High write frequency: If source data changes every second, update overhead may exceed read savings.
  • Complex multi-collection joins: Some computations are too complex to maintain incrementally.
  • Strong consistency required: Computed values may be slightly stale.

Verify with

// Find expensive aggregations that should be pre-computed
db.setProfilingLevel(1, { slowms: 100 }) // Disable afterwards
db.system.profile.find({
  "command.aggregate": { $exists: true },
  millis: { $gt: 100 }
}).sort({ millis: -1 })

// Check if same aggregation runs repeatedly
db.system.profile.aggregate([
  { $match: { "command.aggregate": { $exists: true } } },
  { $group: {
    _id: "$command.pipeline",
    count: { $sum: 1 },
    avgMs: { $avg: "$millis" }
  }},
  { $match: { count: { $gt: 100 } } }  // Repeated 100+ times
])
// High count + high avgMs = candidate for computed pattern

Reference: Computed Schema Pattern