Searching MongoDB collections becomes more complicated as application data grows. A basic query works well when users know the exact product name, customer ID, or document field they want. But real users often search differently.
Someone might search for "wireless headphones with noise cancellation" even though the product description contains "Bluetooth headset with active noise reduction." A normal MongoDB filter may not return the expected result because the wording is different.
Full-text search solves a different problem from ordinary database filtering. It analyzes text, identifies searchable terms, and ranks matching documents according to relevance.
Percona Search for MongoDB brings this capability to self-managed MongoDB deployments. It uses a dedicated search process called mongot, which maintains search indexes and handles search queries alongside Percona Server for MongoDB.
With this approach, developers can add relevance-based search without building a separate Elasticsearch or OpenSearch cluster for every application.
What Is Percona Search for MongoDB?
Percona Search for MongoDB adds full-text and vector search capabilities to Percona Server for MongoDB 8.3 and later.
It uses Apache Lucene to create and maintain search indexes. The search engine runs as a separate process called mongot, while mongod continues to store application documents and handle normal database operations.
The two processes have different responsibilities:
mongod stores documents and handles database operations.
mongot builds and maintains search indexes.
mongot processes full-text and vector search requests.
mongod retrieves the matching documents and returns them to the application.
Applications continue connecting to MongoDB through the normal database connection. They do not connect directly to mongot.
This separation is useful because search indexing and query processing can operate independently of the main database process, while the application continues using MongoDB aggregation pipelines.
Percona Search for MongoDB version 1.70.5-3 reached general availability on November 3, 2026. This release supports production use and includes full-text search, vector search, hybrid search, and automatic embedding capabilities.
For this article, the focus is full-text search. Vector search is a separate capability that uses embeddings to find documents based on semantic similarity.
How Full-Text Search Works
A conventional MongoDB query generally compares stored values against the conditions supplied by an application.
For example:
db.products.find({
name: "Wireless Headphones"
});
This works when the stored value matches the expected condition. It is not designed to understand that "Bluetooth headphones with active noise cancellation" might describe the same type of product.
Full-text search uses an index that breaks text into searchable terms. When a document is inserted or updated, the search service maintains the corresponding index.
When a search request arrives, mongot evaluates the query against the index and identifies relevant documents. MongoDB then retrieves the matching records.
The indexing process works in three main stages:
mongot performs an initial synchronization and reads the existing collection data.
It creates a Lucene-based search index.
It opens a change stream and applies subsequent inserts, updates, and deletes to keep the index synchronized.
This means developers do not need to manually rebuild the complete search index whenever a document changes.
The initial index build can still take time for large collections. The search index should be monitored until it reaches the READY state before the application starts depending on it.
Prepare the MongoDB Environment
Before creating a search index, make sure the deployment meets the compatibility requirements.
Percona Search for MongoDB requires Percona Server for MongoDB 8.3 or later. The mongot process must also be installed, configured, and connected to the database deployment.
The deployment topology determines how mongot is positioned.
In a replica set, the search service runs alongside the relevant MongoDB deployment components. In a sharded cluster, mongos routes search requests to the appropriate shards and merges the results.
The application continues connecting to mongod or mongos. Search configuration and service communication are handled internally.
A production deployment should also account for the search service's own resource requirements. Search indexes consume storage, and indexing and querying require CPU and memory. These resources should be included in capacity planning rather than treating search as a feature with no additional infrastructure cost.
Percona provides installation instructions for the mongot service and deployment guidance for supported topologies. Follow the instructions for the specific operating system and deployment architecture rather than copying configuration from a different environment.
Create a Full-Text Search Index
Once mongot is running and connected, create a search index on the collection.
Consider an application that stores product information:
{
_id: 101,
name: "Wireless Headphones",
description: "Bluetooth headphones with active noise cancellation",
category: "Electronics",
brand: "SoundWave",
price: 2499
}
The application needs to search product names and descriptions. A search index can cover both fields.
Run the following command in mongosh:
db.products.createSearchIndex(
"product_search",
"search",
{
mappings: {
dynamic: false,
fields: {
name: {
type: "string"
},
description: {
type: "string"
},
category: {
type: "string"
},
brand: {
type: "string"
}
}
}
}
);
This creates an index named product_search and explicitly defines the fields that should be searchable.
The dynamic setting is disabled because the application only needs to index selected fields. This prevents unrelated fields from automatically becoming part of the search index.
For example, the price field does not need to be indexed as text because it is better handled through numeric filtering.
Percona Search also supports dynamic mappings. They can be useful when document structures change frequently, but static mappings provide more control over which fields are indexed and how they are analyzed.
After creating the index, check its status:
db.products.getSearchIndexes("product_search");
Wait until the index reports READY and queryable as true. Creating an index is asynchronous, so attempting to search immediately can fail while the initial indexing process is still running.
Run Your First Full-Text Search
After the index is ready, use the $search aggregation stage to retrieve matching documents.
For example, a user searches for "noise cancellation":
db.products.aggregate([
{
$search: {
index: "product_search",
text: {
query: "noise cancellation",
path: ["name", "description"]
}
}
}
]);
The query searches both the name and description fields.
The $search stage returns matching documents ordered by relevance. This is different from a regular find operation, where documents are generally returned according to the query and sort conditions rather than a full-text relevance score.
You can also return the score to understand why a document appears in the result set:
db.products.aggregate([
{
$search: {
index: "product_search",
text: {
query: "noise cancellation",
path: ["name", "description"]
}
}
},
{
$project: {
name: 1,
description: 1,
category: 1,
score: {
$meta: "searchScore"
}
}
}
]);
The score is useful when evaluating search behavior. A higher score generally indicates a stronger match according to the configured search logic.
However, it should not be treated as a percentage or a direct measure of user satisfaction. Search relevance needs to be evaluated against representative application queries.
Combine Text Search With Additional Conditions
A product search application rarely needs text matching alone.
Suppose a customer searches for "wireless headphones" and wants results only from the Electronics category with a price below 5,000.
The compound operator can combine text matching with additional conditions.
db.products.aggregate([
{
$search: {
index: "product_search",
compound: {
must: [
{
text: {
query: "wireless headphones",
path: ["name", "description"]
}
}
],
filter: [
{
equals: {
path: "category",
value: "Electronics"
}
},
{
range: {
path: "price",
lte: 5000
}
}
]
}
}
},
{
$project: {
name: 1,
description: 1,
price: 1,
score: {
$meta: "searchScore"
}
}
}
]);
The must condition requires the text search to match. The filter conditions restrict the results to the requested category and price range.
This distinction matters. Filters narrow the result set without contributing to the relevance score in the same way as scoring text conditions.
The price field must also have a compatible mapping for the range operator. In a production index definition, configure fields according to the operators the application intends to use.
Improve Search Results With Fuzzy Matching
Users do not always enter correctly spelled search terms. They may make typing mistakes, omit a character, or enter a slightly different version of a product name.
Percona Search supports fuzzy text matching.
For example:
db.products.aggregate([
{
$search: {
index: "product_search",
text: {
query: "headphons",
path: ["name", "description"],
fuzzy: {
maxEdits: 1,
prefixLength: 2
}
}
}
},
{
$project: {
name: 1,
description: 1,
score: {
$meta: "searchScore"
}
}
}
]);
The query contains a spelling mistake in "headphons". Fuzzy matching allows the search engine to consider terms that differ by a limited number of edits.
The maxEdits setting controls the allowed edit distance, while prefixLength specifies how many initial characters must match.
Fuzzy matching should be used carefully. Increasing the allowed differences can return more results, but some of them may be unrelated to what the user intended.
For a product catalogue, it is worth testing common spelling mistakes and short search terms before enabling fuzzy matching across every query.
Keep the Search Index in Sync
A search index is useful only when it represents the current collection data.
Percona Search uses change streams to detect document changes and update the search index. Applications do not need to rebuild the entire index after every insert or update.
However, indexing is not the same as updating a document directly inside mongod. The search service must process the change before the updated content becomes available through the search index.
For applications with strict freshness requirements, test the time between a database write and the document becoming searchable.
Also monitor the index status and mongot logs. A failed synchronization process can leave the search experience behind the underlying collection.
If a field is added to the collection but is not covered by a static mapping, update the search index definition before expecting that field to participate in queries.
What to Consider Before Using Percona Search in Production
Percona Search adds search capabilities, but it also introduces another service that needs to be operated.
A few decisions deserve attention before production deployment.
First, estimate index storage requirements. The search index is maintained separately from the original MongoDB documents, so disk planning should account for both.
Second, monitor CPU and memory consumption. Initial indexing and complex queries can use substantial resources, especially for large collections.
Third, choose field mappings based on actual search requirements. Indexing every field can increase storage and indexing work without improving the application.
Finally, test relevance using real search terms. A query that works against a small development collection may behave differently when the production dataset contains more products, descriptions, and similar terms.
Percona Search is free to use and does not require a paid edition or license-gated search features. It is published under the Server Side Public License, so organizations should still review the license terms and their own software distribution requirements.
Conclusion
Percona Search for MongoDB provides full-text search for self-managed Percona Server for MongoDB deployments. It uses mongot and Apache Lucene to maintain search indexes while allowing applications to continue using MongoDB aggregation pipelines.
Developers can create indexes, search across multiple text fields, combine text queries with filters, and use fuzzy matching to handle common typing mistakes.
The main benefit is that applications can add relevance-based search without introducing a separate search database cluster. However, the search service still needs its own deployment, resource planning, index monitoring, and operational checks.
For applications that already store their data in Percona Server for MongoDB, this provides a practical way to introduce full-text search while keeping application data and search capabilities within the same database platform.
Join the conversation! Your thoughts help the community grow.