Overview
MongoDB Atlas Search is a full-text search engine built on Apache Lucene, integrated directly into MongoDB Atlas. It uses aggregation pipelines with the$search stage to query data. While this tight integration is convenient for MongoDB users, it also means your search is coupled to your database and constrained by the aggregation pipeline syntax.
Meilisearch offers a simpler, faster alternative with typo tolerance, faceted search, and hybrid search out of the box — all through a straightforward REST API.
This guide walks you through reading documents from a MongoDB collection and importing them into Meilisearch using a script in JavaScript, Python, or Ruby. You can also skip directly to the finished script.
The migration process consists of four steps:
- Export your data from MongoDB
- Prepare your data for Meilisearch
- Import your data into Meilisearch
- Configure your Meilisearch index settings (optional)
This guide includes examples in JavaScript, Python, and Ruby. The packages used:
- JavaScript:
mongodb6.x,meilisearch(compatible with Meilisearch v1.0+) - Python:
pymongo4.x,meilisearch - Ruby:
mongo2.x,meilisearch
Export your MongoDB data
Initialize project
Install dependencies
Create MongoDB client
You need your MongoDB connection string (URI). For Atlas, this is available in your cluster’s connection settings.MONGODB_URI with your MongoDB connection string (for example, mongodb+srv://user:password@cluster.mongodb.net/myDatabase).
Fetch data from MongoDB
Use thefind() method to retrieve all documents from a collection. For large collections, process documents in batches using a cursor.
YOUR_DATABASE_NAME and YOUR_COLLECTION_NAME with your MongoDB database and collection names.
Prepare your data
MongoDB documents use_id as the primary key, which is typically an ObjectId. Meilisearch requires a string or integer primary key, so you need to convert _id to a string.
Meilisearch stores documents as flat JSON objects. If your MongoDB documents use deeply nested objects, only top-level fields can be used for filtering, sorting, and searching. You can keep nested objects for display purposes, but consider flattening fields you need to filter on. For example,
{ "author": { "name": "John" } } can stay as-is if you only display it, but you should add "author_name": "John" as a top-level field if you need to filter by author name.Handle geo data
MongoDB uses GeoJSON for location data, typically stored as{ type: "Point", coordinates: [longitude, latitude] }. Meilisearch uses a _geo object with lat and lng. Note that MongoDB stores coordinates in [longitude, latitude] order.
Import your data into Meilisearch
Create Meilisearch client
Create a Meilisearch client by passing the host URL and API key of your Meilisearch instance. The easiest option is to use the automatically generated admin API key.MEILI_HOST, MEILI_API_KEY, and MEILI_INDEX_NAME with your Meilisearch host URL, API key, and target index name. Meilisearch will create the index if it doesn’t already exist.
Upload data to Meilisearch
Use the Meilisearch client methodaddDocumentsInBatches to upload all records in batches of 100,000.
Finished script
Configure your index settings
Meilisearch’s default settings deliver relevant, typo-tolerant search out of the box. Unlike MongoDB Atlas Search, which requires you to define search index mappings before you can search, Meilisearch indexes all fields automatically.Key conceptual differences
MongoDB Atlas Search requires you to create search indexes with field mappings (dynamic or static) before you can run$search queries. Search behavior is configured through the aggregation pipeline using stages like $search, $searchMeta, and $vectorSearch. Each query requires constructing a pipeline with specific operators like text, compound, range, and near.
Meilisearch takes a simpler approach: all fields are automatically indexed and searchable by default. You refine behavior through index settings (which affect all searches) and search parameters (which affect a single query). Features like typo tolerance, prefix search, and ranking work without any configuration.
This means most Atlas Search index configurations have no direct equivalent in Meilisearch because the behavior is automatic. You don’t need to configure analyzers, define field mappings, or create search indexes before querying.
Configure embedders
If you used MongoDB Atlas Vector Search ($vectorSearch), you can replace it with Meilisearch’s built-in hybrid search. The key difference: with Atlas Vector Search, your application must compute vectors before indexing and searching. With Meilisearch, you configure an embedder once and Meilisearch handles all embedding automatically — both at indexing time and at search time.
This means you can remove all embedding logic from your application code. Instead of calling an embedding API, computing vectors, and sending them alongside your aggregation pipeline, you simply send documents and text queries to Meilisearch.
Configure an embedder source such as OpenAI, HuggingFace, or a custom REST endpoint:
documentTemplate controls what text is sent to the embedding model. Adjust it to match the fields in your documents. Meilisearch will automatically embed all existing documents and keep vectors up to date as you add, update, or delete documents.
For more options including HuggingFace models, Ollama, and custom REST endpoints, see configuring embedders.
Alternative: use existing vectors with userProvided embedder
Alternative: use existing vectors with userProvided embedder
If you already have precomputed vectors stored alongside your MongoDB documents and want to keep them, you can include them in the Replace
_vectors field during migration and configure a userProvided embedder:1536 with the dimension of your vectors. With this approach, you remain responsible for computing and providing vectors when adding or updating documents. You also need to compute query vectors client-side when searching.To include vectors during migration, modify the prepareDocuments function to extract your vector field into _vectors:Configure filterable and sortable attributes
In MongoDB Atlas Search, you define which fields support faceting and filtering through your search index mappings. In Meilisearch, configurefilterableAttributes and sortableAttributes:
What you gain
Migrating from MongoDB Atlas Search to Meilisearch gives you several advantages:- No search index definitions — Meilisearch indexes all fields automatically. No need to create or maintain search index mappings
- Simpler query syntax — Replace complex aggregation pipelines with a flat JSON search request
- Typo tolerance out of the box — no configuration required
- Hybrid search combining keyword relevancy and semantic similarity in a single query, with automatic embedding
- Faceted search with value distributions for building filter UIs
- Highlighting of matching terms in results
- Synonyms and stop words support
- Decoupled search — Your search engine is independent of your database, so you can scale, tune, and deploy each separately
Settings and parameters comparison
The below tables compare MongoDB Atlas Search concepts with their Meilisearch equivalents.Search index configuration
| MongoDB Atlas Search | Meilisearch | Notes |
|---|---|---|
| Dynamic field mappings | Automatic | Meilisearch indexes all fields by default |
| Static field mappings | searchableAttributes / filterableAttributes | Use these to restrict or reorder searchable fields and enable filtering |
Lucene analyzer (lucene.standard, etc.) | Automatic | Meilisearch uses a built-in language-aware analyzer |
| Custom analyzers | separatorTokens / nonSeparatorTokens | Customize word boundary behavior |
storedSource | displayedAttributes | Control which fields appear in results |
synonyms (in index definition) | synonyms | Define equivalent terms |
type: "string" mapping | Automatic | Field types are inferred |
type: "number" mapping | Automatic | Field types are inferred |
type: "geo" mapping | _geo field with lat/lng | Add _geo to filterableAttributes and sortableAttributes |
Search operators
| MongoDB Atlas Search | Meilisearch | Notes |
|---|---|---|
$search with text operator | q search param | Meilisearch searches all searchableAttributes by default |
$search with phrase operator | q search param | Use "quoted phrase" in the query string for phrase matching |
$search with wildcard operator | Automatic prefix search | Meilisearch applies prefix search on the last query word by default |
$search with regex operator | No direct equivalent | Use filter for exact matching on specific field values |
$search with compound (must/should/mustNot/filter) | q + filter | Combine search query with filter expressions using AND, OR, NOT |
$search with range operator | filter search param | Use operators like field > value or field value1 TO value2 |
$search with near (geo) | _geoRadius(lat, lng, radius) or _geoBoundingBox([lat, lng], [lat, lng]) in filter | Requires _geo in filterableAttributes |
$vectorSearch | hybrid + auto-embedder | No need to precompute vectors — Meilisearch embeds queries automatically |
$searchMeta with facet collector | facets search param | Returns value distributions for each facet |
highlight option in $search | attributesToHighlight + highlightPreTag + highlightPostTag | Search params |
$sort stage after $search | sort search param | Requires sortableAttributes |
$skip / $limit stages | offset / limit or page / hitsPerPage | Search params |
scoreDetails: true | showRankingScoreDetails | Search param |
count in $searchMeta | Automatic | Meilisearch returns estimatedTotalHits (or totalHits with exhaustive pagination) |
Index settings
| MongoDB Atlas Search | Meilisearch | Notes |
|---|---|---|
| Search index definition | Automatic | No index definition needed before searching |
| Analyzer configuration | Automatic | Built-in language-aware text processing |
storedSource | displayedAttributes | Control which fields appear in results |
synonyms mapping | synonyms | Define equivalent terms |
| Index on specific fields | searchableAttributes | All fields searchable by default; use this to restrict |
| Atlas cluster scaling | Automatic (Meilisearch Cloud) | Meilisearch Cloud handles scaling |
Query comparison
This section shows how common MongoDB Atlas Search aggregation pipelines translate to Meilisearch search requests.Full-text search
MongoDB Atlas Search:searchableAttributes by default. To restrict to a specific field, use the attributesToSearchOn search parameter.
Filtered search
MongoDB Atlas Search:Attributes used in
filter must first be added to filterableAttributes.Sorting
MongoDB Atlas Search:Attributes used in
sort must first be added to sortableAttributes.Faceted search
MongoDB Atlas Search:filter to narrow results by range.
Geo search
MongoDB Atlas Search:The
_geo attribute must be added to both filterableAttributes and sortableAttributes. Note that MongoDB uses [longitude, latitude] order in GeoJSON while Meilisearch uses lat, lng order.Vector / semantic search
With Atlas Vector Search, you must compute the query vector yourself before searching. With Meilisearch, you configure an auto-embedder once and just send natural language queries: MongoDB Atlas Vector Search:q text for you. Setting semanticRatio to 1.0 performs pure semantic search — but without managing vectors in your application code. Set semanticRatio to 0.5 to combine keyword and semantic results in a single hybrid query, something that would require running both $search and $vectorSearch pipelines separately with Atlas.
API methods
This section compares MongoDB Atlas Search operations with Meilisearch API endpoints.| Operation | MongoDB Atlas Search | Meilisearch |
|---|---|---|
| Create search index | db.collection.createSearchIndex() | POST /indexes (automatic) |
| Delete search index | db.collection.dropSearchIndex() | DELETE /indexes/{index_uid} |
| List search indexes | db.collection.getSearchIndexes() | GET /indexes |
| Full-text search | db.collection.aggregate([{ $search: ... }]) | POST /indexes/{index_uid}/search |
| Vector search | db.collection.aggregate([{ $vectorSearch: ... }]) | POST /indexes/{index_uid}/search (with hybrid) |
| Facet search | db.collection.aggregate([{ $searchMeta: ... }]) | POST /indexes/{index_uid}/search (with facets) |
| Multi-search | Multiple aggregation pipelines | POST /multi-search |
| Add documents | db.collection.insertMany() | POST /indexes/{index_uid}/documents |
| Get document | db.collection.findOne() | GET /indexes/{index_uid}/documents/{id} |
| Delete document | db.collection.deleteOne() | DELETE /indexes/{index_uid}/documents/{id} |
| Delete by filter | db.collection.deleteMany() | POST /indexes/{index_uid}/documents/delete |
| Update settings | Update search index definition | PATCH /indexes/{index_uid}/settings |
| Get settings | db.collection.getSearchIndexes() | GET /indexes/{index_uid}/settings |
| API keys | Atlas access management | POST /keys |
| Health check | Atlas monitoring | GET /health |
| Task status | Atlas index build status | GET /tasks/{task_uid} |