Time-series data is common in applications that collect information continuously. Examples include temperature readings from sensors, application performance metrics, stock prices, equipment status, and server monitoring data. These records usually contain a timestamp, a set of measurements, and information identifying the source.
Storing this type of data in a regular MongoDB collection is possible, but time-series collections provide storage and query optimizations designed specifically for timestamped measurements.
Two important decisions when designing a time-series collection are granularity and data retention. Granularity influences how MongoDB groups measurements into internal buckets, while retention determines how long the database keeps historical data. Choosing these settings carefully can improve query performance, control storage growth, and simplify database maintenance.
This article explains how MongoDB time-series collections work, how to select appropriate granularity, and how to configure data retention for practical applications.
Understanding MongoDB Time-Series Collections
A time-series collection stores documents containing measurements associated with time. MongoDB groups related measurements into internal buckets instead of storing every measurement as an entirely independent storage unit.
For example, an industrial monitoring application might collect temperature readings every five seconds. Each reading contains a timestamp, a sensor identifier, and the measured temperature.
A document might look like this:
{
timestamp: ISODate("2026-10-29T10:00:00Z"),
metadata: {
sensorId: "sensor-101",
location: "plant-a"
},
temperature: 21.4,
humidity: 43.2
}
The document contains three important categories of information:
timestamp identifies when the measurement was recorded.metadata identifies the sensor and its location.temperature and humidity contain the actual measurements.
MongoDB uses the timestamp and metadata to organize measurements into buckets. This arrangement can reduce storage overhead and improve operations involving time ranges.
Creating a Time-Series Collection
You can create a time-series collection using db.createCollection().
db.createCollection("sensorReadings", {
timeseries: {
timeField: "timestamp",
metaField: "metadata",
granularity: "seconds"
},
expireAfterSeconds: 60 * 60 * 24 * 30
});
Here is what each setting means:
| Setting | Purpose |
|---|
timeField | Specifies the field containing the measurement timestamp. |
metaField | Identifies the field containing metadata associated with a series. |
granularity | Selects a predefined time-series bucketing configuration. |
expireAfterSeconds | Configures automatic expiration of measurements after the specified retention period. |
The timestamp field should contain BSON Date values. The metadata field is optional, but it is useful when measurements belong to identifiable devices, sensors, locations, or other stable sources.
The retention value in this example is 30 days, expressed in seconds.
Granularity and retention solve different problems. Granularity affects how MongoDB groups measurements, while retention controls their lifecycle.
How to Choose the Right Granularity
Granularity is one of the most important configuration decisions for a time-series collection. It helps MongoDB determine appropriate bucket boundaries and grouping behavior.
MongoDB provides three predefined granularity values:
These options represent different expected measurement frequencies. They should be selected according to the rate at which data arrives and the application's query patterns.
Seconds Granularity
Use seconds when measurements arrive frequently, such as every few seconds or every few tens of seconds.
Common examples include:
- Industrial sensors recording machine conditions.
- Server monitoring systems collecting CPU and memory measurements.
- IoT devices reporting temperature, pressure, or humidity.
- Applications recording frequent operational metrics.
For example, a sensor that records a temperature reading every five seconds may use seconds granularity.
db.createCollection("fastSensorReadings", {
timeseries: {
timeField: "timestamp",
metaField: "metadata",
granularity: "seconds"
}
});
This configuration is a reasonable starting point for frequently updated sensors. However, the actual measurement frequency, metadata consistency, query patterns, and bucket behavior should still be evaluated under realistic workloads.
Minutes Granularity
Use minutes when measurements arrive less frequently than high-frequency telemetry but still arrive regularly throughout the day.
Typical examples include:
- Environmental monitoring systems.
- Building management applications.
- Periodic equipment health reports.
- Business metrics collected at regular intervals.
For example, a monitoring application that records a reading every minute could use the following configuration:
db.createCollection("environmentReadings", {
timeseries: {
timeField: "timestamp",
metaField: "metadata",
granularity: "minutes"
}
});
This configuration is appropriate when the expected measurement interval is closer to minutes than seconds.
Do not select minutes granularity simply because application reports group measurements by minute. The frequency of incoming measurements and the collection's workload are more important than the display format used by a dashboard.
Hours Granularity
Use hours when measurements arrive relatively infrequently, such as hourly readings from devices or periodic operational reports.
Examples include:
- Agricultural monitoring systems.
- Long-term environmental measurements.
- Equipment readings collected at hourly intervals.
- Periodic business or infrastructure statistics.
db.createCollection("hourlyReadings", {
timeseries: {
timeField: "timestamp",
metaField: "metadata",
granularity: "hours"
}
});
This setting is suitable when measurements are relatively sparse over time.
If the application later starts collecting readings every few seconds, revisit the collection design rather than assuming that the existing configuration will remain optimal.
Granularity Comparison
| Granularity | Typical workload | Example |
|---|
seconds | Frequent measurements | Server metrics collected every five seconds |
minutes | Regular measurements at moderate intervals | Environmental readings collected every minute |
hours | Infrequent measurements | Equipment readings collected hourly |
These are practical guidelines rather than strict limits. The best choice depends on the actual arrival pattern and the queries the application needs to execute.
MongoDB versions that support custom bucket span and rounding settings may offer more control than the predefined granularity values. Those options are version-dependent, so verify the capabilities of the MongoDB server you deploy before using them.
Designing the Metadata Field
The metadata field helps MongoDB identify measurements that belong to the same series. Its design can affect how effectively the database groups measurements into buckets.
Consider a monitoring application with hundreds of sensors across several manufacturing plants.
A useful metadata structure might be:
{
timestamp: ISODate("2026-10-29T10:00:00Z"),
metadata: {
sensorId: "sensor-101",
plantId: "plant-a"
},
temperature: 21.4
}
The sensor and plant identifiers help describe the source of the measurement.
Keep Metadata Stable
Metadata should contain attributes that remain consistent across measurements belonging to the same series.
Good metadata fields include:
- Sensor ID.
- Device ID.
- Machine ID.
- Location ID.
- Equipment category, when it remains stable for that series.
Avoid putting frequently changing measurement values into metadata.
For example, temperature should remain a measurement field rather than becoming part of the metadata object. If the temperature changes with every reading, using it as metadata can prevent related measurements from being grouped effectively.
Metadata design should also reflect how the application queries its data. If the application frequently retrieves readings for a particular sensor, the sensor identifier should be easy to filter.
Inserting and Querying Time-Series Data
After creating the collection, insert documents with valid timestamps and measurement values.
Insert Sample Measurements
db.sensorReadings.insertMany([
{
timestamp: ISODate("2026-10-29T10:00:00Z"),
metadata: {
sensorId: "sensor-101",
location: "plant-a"
},
temperature: 21.4,
humidity: 43.2
},
{
timestamp: ISODate("2026-10-29T10:00:05Z"),
metadata: {
sensorId: "sensor-101",
location: "plant-a"
},
temperature: 21.7,
humidity: 43.5
},
{
timestamp: ISODate("2026-10-29T10:00:10Z"),
metadata: {
sensorId: "sensor-101",
location: "plant-a"
},
temperature: 21.9,
humidity: 43.8
}
]);
The timestamps use UTC, which makes measurements easier to compare across devices and geographic locations.
For production applications, validate incoming timestamps and measurement values before inserting documents. Invalid timestamps or inconsistent metadata can complicate queries and data analysis.
Query a Specific Time Range
A common requirement is to retrieve measurements for one sensor during a specific period.
db.sensorReadings.find({
"metadata.sensorId": "sensor-101",
timestamp: {
$gte: ISODate("2026-10-29T10:00:00Z"),
$lt: ISODate("2026-10-29T11:00:00Z")
}
}).sort({
timestamp: 1
});
This query filters by sensor ID and selects measurements recorded within a one-hour interval.
Using an inclusive lower boundary with $gte and an exclusive upper boundary with $lt is useful for processing consecutive time windows. It avoids including the same boundary measurement in two adjacent intervals.
For example, one query can cover 10:00 to 11:00, while the next covers 11:00 to 12:00.
For frequently executed queries, inspect the available indexes and use MongoDB's query explain facilities to evaluate execution plans. Index options and restrictions for time-series collections vary by server version, so verify support before adding an index.
Configuring Data Retention
Time-series data can grow quickly because measurements continue arriving even when older records are rarely accessed.
Retention policies help control storage growth by automatically removing measurements that are no longer needed.
MongoDB supports expiration for time-series collections through the expireAfterSeconds collection option.
Set a Retention Period During Collection Creation
The following example configures a 30-day retention period:
db.createCollection("sensorReadings", {
timeseries: {
timeField: "timestamp",
metaField: "metadata",
granularity: "seconds"
},
expireAfterSeconds: 2592000
});
The value 2592000 represents 30 days in seconds.
MongoDB uses the measurement timestamps to determine expiration. The retention period is relative to the time recorded in the timeField, not simply the time when the document was inserted.
This distinction matters when devices upload measurements late. A reading uploaded today with a timestamp from several months ago may already be eligible for expiration under the configured policy.
Change Retention for an Existing Collection
Retention requirements can change as an application evolves. For example, a monitoring system might initially keep measurements for 30 days and later need to retain them for 90 days.
On MongoDB versions that support modifying time-series expiration settings through collMod, you can use a command such as:
db.runCommand({
collMod: "sensorReadings",
expireAfterSeconds: 7776000
});
The value 7776000 represents 90 days.
Before running this command, verify that your MongoDB version supports the operation and that the collection has the expected configuration. Test retention changes in a non-production environment when possible.
Increasing retention does not recover measurements that have already been deleted. Similarly, reducing retention can make more data eligible for removal, so evaluate the impact before changing the setting.
Understand How Expiration Works
A configured retention period is not an exact deletion deadline.
MongoDB's time-series storage uses buckets containing multiple measurements. Expiration and cleanup operate with this bucket-based storage model, and background cleanup is asynchronous.
Consequently, an expired measurement may remain available for some time after its nominal expiration threshold. Do not use time-series TTL expiration as a mechanism that guarantees deletion at an exact second.
If the application has legal, contractual, or security requirements for data deletion, verify that the complete retention and deletion process satisfies those requirements. A retention setting alone should not be treated as proof of immediate or exact removal.
Granularity vs. Retention
Granularity and retention are related to time-series design, but they control different aspects of the collection.
| Consideration | Granularity | Retention |
|---|
| Primary purpose | Controls the expected measurement grouping pattern | Controls how long measurements are retained |
| Main input | Measurement frequency and workload | Business, operational, and compliance requirements |
| Effect on storage | Influences bucket organization and storage efficiency | Limits how much historical data remains |
| Typical adjustment | Review collection design and supported bucket settings | Modify the expiration configuration when supported |
| Main risk | Poorly matched grouping behavior may reduce efficiency | Data may expire earlier than intended or remain longer than expected |
For example, an application can use seconds granularity while retaining data for only seven days. Another application can use hours granularity while retaining measurements for several years.
Neither setting determines the other.
Best Practices for Production Applications
Choose Granularity Before Loading Large Volumes
Estimate how frequently measurements arrive and validate the choice with representative data. Changing the collection design after substantial data has accumulated may require creating a new collection and migrating measurements.
Keep Metadata Consistent
Use stable identifiers and avoid unnecessary changes in metadata structure. Consistent metadata helps MongoDB organize related measurements more effectively.
Define Retention Based on Actual Requirements
Do not retain every measurement indefinitely by default. Consider operational needs, storage costs, analytical requirements, and applicable data-retention policies.
Different categories of measurements may need different retention periods. Separate collections can help when data classes have significantly different lifecycle requirements.
Test Queries With Realistic Data
A collection containing a few hundred records may behave differently from one containing millions of measurements across thousands of devices.
Test the queries used by dashboards, reports, and alerting systems with representative data volumes. Review query plans and indexes supported by your MongoDB version.
Monitor Late and Out-of-Order Measurements
Some devices temporarily lose connectivity and upload historical readings later. Other systems may produce measurements out of chronological order.
Validate timestamp handling and test how delayed data interacts with retention policies. Ensure that ingestion, querying, and expiration behavior match the application's requirements.
Common Mistakes to Avoid
| Mistake | Why it matters | Better approach |
|---|
| Choosing granularity without examining ingestion frequency | Bucket organization may not fit the actual workload | Measure typical and peak measurement intervals |
| Putting changing values in metadata | Measurements may be grouped less effectively | Keep changing readings in measurement fields |
| Treating TTL as immediate deletion | Background expiration is asynchronous | Allow for cleanup delays and validate deletion requirements |
| Assuming retention begins at insertion time | Expiration is based on the configured time field | Validate timestamps and account for delayed ingestion |
| Ignoring index restrictions | An unsupported index configuration may fail or be unavailable | Check the deployed MongoDB version and query plans |
| Using one retention policy for every data category | Different data may have different lifecycle requirements | Define retention according to business needs |
Advantages and Disadvantages
Advantages
- Time-series collections are designed for timestamped measurements and can reduce storage overhead through bucket-based organization.
- Granularity settings help match collection behavior to the expected measurement frequency.
- Retention policies reduce the need for manual cleanup of historical measurements.
- Time-range queries make it practical to retrieve measurements for monitoring, reporting, and analysis.
Disadvantages
- Granularity must be chosen with the workload in mind.
- Time-series collections have specific restrictions that can differ from regular MongoDB collections.
- Background expiration does not guarantee deletion at an exact moment.
- Changes to collection design may require migration or additional operational work.
Summary
MongoDB time-series collections provide a practical way to store and query timestamped measurements from sensors, devices, and monitoring systems.
Choose seconds, minutes, or hours granularity according to the expected measurement frequency and validate the decision with realistic workloads. Use stable metadata to identify the source of each measurement, store timestamps consistently, and design queries around the application's most common time ranges.
For retention, configure expireAfterSeconds according to business requirements and understand that expiration is asynchronous. Verify version-specific behavior before changing collection settings or relying on particular index capabilities.
The main principle is to design granularity around how measurements arrive and retention around how long the application needs to keep them. Treating these as separate decisions helps create a time-series collection that remains manageable as data volume grows.
Join the conversation! Your thoughts help the community grow.