MongoDB Time Series Collections

MongoDB time series collections store measurements whose meaning depends on time, such as sensor readings, application metrics, prices, or website traffic. MongoDB groups nearby measurements into internal buckets to reduce storage and improve time-based queries.

You work with a time series collection through normal MongoDB queries, but you define its time field and optional metadata when you create it.

Structure of Time Series Data

A useful measurement usually contains three parts:

  • Time: the date and time when the measurement occurred.
  • Metadata: stable information that identifies the source, such as a sensor ID or server name.
  • Metrics: values that change over time, such as temperature, CPU usage, or order count.

Example document:

{
    // Required date value used by the collection timeField
    timestamp: ISODate("2026-09-03T10:00:00Z"),

    // Stable information used to group and filter measurements
    metadata: {
        sensorId: "IND-101",
        city: "Indore"
    },

    // Values measured at this point in time
    temperature: 29.4,
    humidity: 61
}

Create a Time Series Collection

Use db.createCollection() with a timeseries configuration. The timeField is required. The metaField and granularity settings are optional but important for efficient storage.

Example:

// Create a collection for readings recorded every few minutes
db.createCollection("weatherReadings", {
    timeseries: {
        timeField: "timestamp",
        metaField: "metadata",
        granularity: "minutes"
    },
    expireAfterSeconds: 2592000 // Keep data for approximately 30 days
})

Output:

{ ok: 1 }

Version note: Time series collections were introduced in MongoDB 5.0. Current releases provide additional indexing, update, sharding, and performance improvements.

Choose the Right Fields

The time field must contain a BSON date. MongoDB uses its values to place measurements into time-ordered buckets.

Choose metadata that changes rarely and commonly appears in filters. Do not place changing measurements or unique event values in the metadata object because high-cardinality metadata can create many small buckets.

Setting Good choice Poor choice
timeField Measurement timestamp Formatted date string
metaField Sensor ID and location Temperature or random request ID
metric Temperature and humidity Permanent device identity

Select Granularity

Granularity tells MongoDB how frequently measurements from one source normally arrive. Choose the closest practical interval.

Granularity Approximate maximum bucket span Typical use
seconds 1 hour Frequent metrics or readings
minutes 24 hours Readings every few minutes
hours 30 days Infrequent daily or hourly data

A setting that is too fine can create many lightly filled buckets. A setting that is too coarse can make a narrow query inspect a wider time range than necessary.

Insert Measurements

Insert measurements as normal documents. Use real BSON dates rather than storing timestamps as strings.

Example:

// Add readings from two sensors
db.weatherReadings.insertMany([
    {
        timestamp: ISODate("2026-09-03T10:00:00Z"),
        metadata: { sensorId: "IND-101", city: "Indore" },
        temperature: 29.4,
        humidity: 61
    },
    {
        timestamp: ISODate("2026-09-03T10:05:00Z"),
        metadata: { sensorId: "IND-101", city: "Indore" },
        temperature: 29.8,
        humidity: 60
    },
    {
        timestamp: ISODate("2026-09-03T10:05:00Z"),
        metadata: { sensorId: "LON-204", city: "London" },
        temperature: 18.2,
        humidity: 72
    }
])

Output:

{ acknowledged: true, insertedIds: { '0': ObjectId(...), '1': ObjectId(...), '2': ObjectId(...) } }

Query a Time Range

Filter by stable metadata and a bounded time range. This pattern lets MongoDB avoid unrelated sources and buckets.

Example:

// Read one sensor's measurements for a 15-minute window
db.weatherReadings.find({
    "metadata.sensorId": "IND-101",
    timestamp: {
        $gte: ISODate("2026-09-03T10:00:00Z"),
        $lt: ISODate("2026-09-03T10:15:00Z")
    }
}).sort({ timestamp: 1 })

Output:

[
  { timestamp: ISODate("2026-09-03T10:00:00Z"), metadata: { sensorId: "IND-101", city: "Indore" }, temperature: 29.4, humidity: 61 },
  { timestamp: ISODate("2026-09-03T10:05:00Z"), metadata: { sensorId: "IND-101", city: "Indore" }, temperature: 29.8, humidity: 60 }
]

Aggregate Measurements by Time

Use an aggregation pipeline to calculate summaries for fixed intervals. $dateTrunc places timestamps into consistent time windows.

Example:

// Calculate the average temperature for each hour
db.weatherReadings.aggregate([
    {
        $match: {
            "metadata.sensorId": "IND-101"
        }
    },
    {
        $group: {
            _id: {
                $dateTrunc: {
                    date: "$timestamp",
                    unit: "hour"
                }
            },
            averageTemperature: { $avg: "$temperature" },
            samples: { $sum: 1 }
        }
    },
    {
        // Return the earliest hour first
        $sort: { _id: 1 }
    }
])

Output:

[
  {
    _id: ISODate("2026-09-03T10:00:00Z"),
    averageTemperature: 29.6,
    samples: 2
  }
]

Expire Old Measurements Automatically

The collection-level expireAfterSeconds option removes measurements after the configured age. Expiration uses the time-field value. Removal runs in the background and is not guaranteed to occur at the exact expiration second because MongoDB removes expired buckets during later cleanup passes.

Example:

// Change retention to seven days
db.runCommand({
    collMod: "weatherReadings",
    expireAfterSeconds: 604800
})

Indexes and Sharding

MongoDB 6.3 and later automatically create a compound index on the metadata and time fields for new time series collections. Add another index only after checking real query patterns with explain().

For sharded time series collections, use stable metadata as the shard-key basis. Starting in MongoDB 8.0, shard keys that contain the timeField are deprecated.

Important Limitations

  • You cannot redefine the time field or metadata field after collection creation.
  • Time series updates have restrictions; filters and changes are mainly designed around metadata rather than arbitrary measurement edits.
  • Zone sharding is not supported for time series collections.
  • TTL cleanup is eventual, so expired measurements may remain briefly.
  • A time series collection is unsuitable for data that has no meaningful time order.

Best Practices

  • Store timestamps as BSON dates in a consistent time zone, usually UTC.
  • Keep metadata stable and use it in common filters.
  • Select granularity from the normal interval between measurements from one source.
  • Query bounded time ranges instead of scanning the complete collection.
  • Set a retention period when old measurements have no business value.
  • Test indexes and aggregation pipelines with production-like data volumes.

Conclusion

MongoDB time series collections organize measurements into compressed, time-aware buckets. Define a valid time field, choose stable metadata, match granularity to the arrival rate, and query with both metadata and time bounds. These choices improve storage, retention, and analysis without adding a separate data model.



Found This Page Useful? Share It!
Get the Latest Tutorials and Updates
Join us on Telegram