Atlas Search
Atlas Search embeds a full-text search engine (built on Apache Lucene) directly into your Atlas cluster. Instead of running a separate Elasticsearch/OpenSearch deployment and keeping it in sync, you define a search index on your existing collection and query it with the $search aggregation stage — no data movement required.
Lucene-Based Search vs Basic Text Indexes
| Atlas Search ($search) | |
|---|---|---|
Engine | MongoDB’s built-in tokenizer | Apache Lucene |
Relevance scoring | Basic TF-IDF-like scoring | Rich, tunable relevance (BM25 and more) |
Fuzzy matching / typo tolerance | No | Yes |
Autocomplete | No | Yes (dedicated autocomplete field type) |
Faceting | No | Yes |
Highlighting matched terms | No | Yes |
Availability | Any MongoDB deployment | Atlas only (M10+ recommended for production) |
Creating a Search Index
Search indexes are defined separately from regular MongoDB indexes — through the Atlas UI, Atlas CLI, or the driver's createSearchIndex helper.
Search index definition
db.articles.createSearchIndex(
"default",
{
mappings: {
dynamic: false,
fields: {
title: { type: "string", analyzer: "lucene.standard" },
body: { type: "string" },
tags: { type: "string" },
publishedAt: { type: "date" }
}
}
}
)Basic $search — text Operator
db.articles.aggregate([
{
$search: {
text: {
query: "mongodb performance",
path: ["title", "body"]
}
}
},
{ $limit: 10 },
{ $project: { title: 1, score: { $meta: "searchScore" } } }
])compound — Combining Search Conditions
compound lets you combine multiple clauses with must (required, scores), filter (required, no scoring impact), should (boosts relevance if matched), and mustNot.
db.articles.aggregate([
{
$search: {
compound: {
must: [{ text: { query: "mongodb", path: "body" } }],
filter: [{ range: { path: "publishedAt", gte: ISODate("2025-01-01") } }],
should: [{ text: { query: "performance", path: "title", score: { boost: { value: 3 } } } }]
}
}
}
])Autocomplete
// Index definition needs an autocomplete field type:
// { title: { type: "autocomplete" } }
db.articles.aggregate([
{ $search: { autocomplete: { query: "mongo", path: "title" } } },
{ $limit: 5 }
])Scoring
Every matched document gets a relevance score you can read via { $meta: "searchScore" } and boost with field weights or the score.boost option — letting more important fields or fresher documents rank higher.
Facets
db.articles.aggregate([
{
$searchMeta: {
facet: {
operator: { text: { query: "mongodb", path: "body" } },
facets: {
tagsFacet: { type: "string", path: "tags" },
dateFacet: { type: "date", path: "publishedAt", boundaries: [
ISODate("2024-01-01"), ISODate("2025-01-01"), ISODate("2026-01-01")
] }
}
}
}
}
])
// Returns counts per tag / date bucket alongside the search — great for
// building filter sidebars ("Category (42)", "2025 (12)")When to Use What
Simple keyword search, small collection, no Atlas → basic
$textindex is enough.Relevance ranking, fuzzy matching, autocomplete, faceted search, on Atlas → Atlas Search.
Massive search-specific workload independent of your operational database, or you need capabilities Lucene-on-Atlas doesn’t offer (e.g. vector search at very large scale, specialized ranking plugins) → a dedicated external search engine (Elasticsearch/OpenSearch) may still be worth the operational overhead.
Summary
Atlas Search brings Lucene-powered full-text search into your existing MongoDB cluster — no separate search engine, no data sync pipeline.
$search is the query stage; compound combines multiple conditions with must/filter/should/mustNot.
Supports fuzzy matching, autocomplete, faceting, and tunable relevance scoring that a basic $text index cannot do.
Reach for a dedicated external search engine only when you outgrow what Atlas Search offers or need to decouple search infrastructure entirely.