Next steps: Atlas Search, time series and vector search
Add full-text relevance and vector similarity as pipeline stages, store measurements in time-series collections instead of hand-rolled buckets, and know when another store is the better answer.
Atlas Search
db.orders.aggregate([
{ $search: {
index: "default",
compound: {
must: [ { text: { query: "lamp", path: "title",
fuzzy: { maxEdits: 1 } } } ],
should: [ { text: { query: "priority", path: "tags",
score: { boost: { value: 2 } } } } ],
filter: [ { range: { path: "total", gte: 10 } } ]
}
} },
{ $limit: 10 },
{ $project: { title: 1, score: { $meta: "searchScore" } } }
])- Atlas Search is Lucene-backed and runs as a separate process beside the database, but it is exposed as a
$searchstage, so it composes with the rest of the pipeline. - The index definition decides which fields are text, keyword, autocomplete or date. A field that is not mapped is not searchable, whatever the query says.
- Relevance is tunable with
boost, and$meta: "searchScore"exposes the score so later stages can sort or filter on it. - It is an Atlas feature. Self-managed MongoDB needs a separate search engine alongside it.
💡
Search indexes are eventually consistent with the collection. A document written a moment ago may not be findable yet, so do not use search as the read path immediately after a write within the same request.
Time-series collections
db.createCollection("readings", {
timeseries: {
timeField: "at",
metaField: "sensorId",
granularity: "minutes"
},
expireAfterSeconds: 60 * 60 * 24 * 365
});
db.readings.insertOne({ at: new Date(), sensorId: "s-12", value: 21.4 });
db.readings.aggregate([
{ $match: { sensorId: "s-12", at: { $gte: ISODate("2026-09-01") } } },
{ $group: {
_id: { $dateTrunc: { date: "$at", unit: "hour" } },
avg: { $avg: "$value" },
n: { $sum: 1 }
} }
])- The server groups measurements into buckets automatically, so a time-series collection replaces the hand-rolled bucket pattern.
- Set
metaFieldto the field you filter by most often; measurements are grouped by it inside each bucket, which is what makes the compression effective. granularityis a hint about the interval between measurements, not a limit. A wrong value costs compression rather than correctness.- Documents are effectively append-only. Updates and deletes work, but they are far less efficient than inserts, so treat the data as immutable.
- Use
expireAfterSecondsfor retention instead of a scheduled cleanup job.
Vector search, and when to choose another store
db.products.aggregate([
{ $vectorSearch: {
index: "vector_index",
path: "embedding",
queryVector: queryVec, // same model and dimension as the index
numCandidates: 200,
limit: 10
} },
{ $project: { title: 1, score: { $meta: "vectorSearchScore" } } }
])| Need | Better fit |
|---|---|
| Exact relational constraints and joins | A relational database |
| Full-text relevance off Atlas | A dedicated search engine |
| Sub-millisecond key lookups | A cache or a key-value store |
| Very large analytical scans | A columnar warehouse |
| Millions of vectors with heavy filtering | A dedicated vector database |
- The mechanism is
$vectorSearchagainst an Atlas Search index whose definition declares the field, the number of dimensions and the similarity metric. It has to be the first stage of the pipeline. - Vector search compares embeddings by similarity, so the query vector must come from the same model and dimension as the indexed field — mixing models produces meaningless neighbours.
- Normalise vectors the same way at index time and at query time, or the ranking is dominated by magnitude rather than by direction.
- Hybrid search combines
$vectorSearchwith$searchin a single pipeline, which usually beats either one alone for real queries. - A database is a tool, not a religion. Choose the store that matches the access pattern, and accept the cost of a second system only when the benefit is measurable.
FAQ
Should I move to Atlas for search?
If you are already on Atlas, search becomes a pipeline stage rather than a second system to operate, and that is a real win. If you are self-hosted and search matters, a dedicated engine is usually a better investment than migrating the database.
When is a time-series collection worth it?
When measurements arrive continuously and are queried by time plus a metadata field. Automatic bucketing improves both compression and query speed, and it removes bucket logic you would otherwise maintain by hand.
Related
The aggregation pipeline Data modelling: embedding vs referencing and schema validation
Last refreshed 2026-09-18.