MongoDB’s text search indexes are a surprisingly powerful way to implement full-text search capabilities directly within your database, avoiding the need for a separate search engine like Elasticsearch for many use cases.

Let’s see this in action. Imagine we have a products collection with documents like this:

{
  "_id": ObjectId("60b8f4e2b4b1b1b1b1b1b1b1"),
  "name": "Organic Cotton T-Shirt",
  "description": "A soft and breathable t-shirt made from 100% organic cotton. Perfect for everyday wear.",
  "tags": ["clothing", "organic", "eco-friendly", "casual"]
}
{
  "_id": ObjectId("60b8f4e2b4b1b1b1b1b1b1b2"),
  "name": "Wireless Bluetooth Headphones",
  "description": "Immersive sound quality with noise cancellation. Long-lasting battery life for all-day listening.",
  "tags": ["electronics", "audio", "wireless", "gadget"]
}
{
  "_id": ObjectId("60b8f4e2b4b1b1b1b1b1b1b3"),
  "name": "Stainless Steel Water Bottle",
  "description": "Keep your drinks cold for 24 hours or hot for 12. Durable and leak-proof.",
  "tags": ["kitchenware", "outdoor", "hydration", "eco-friendly"]
}

To enable text search, we first need to create a text index. This index can cover one or more fields.

db.products.createIndex( { name: "text", description: "text", tags: "text" } )

Now, we can perform searches. To find products related to "cotton", we’d use:

db.products.find( { $text: { $search: "cotton" } } )

This query will return the "Organic Cotton T-Shirt" document. If we search for "eco-friendly", it will return both the t-shirt and the water bottle.

The core problem text search indexes solve is efficiently querying unstructured or semi-structured text data. Traditional B-tree indexes are optimized for exact matches or range queries on specific values. For searching within the content of strings (like descriptions or article bodies), a text index tokenizes the text (breaks it into words), stems it (reduces words to their root form, e.g., "running" to "run"), and removes stop words (common words like "the", "a", "is"). It then builds an inverted index, mapping each token to the documents containing it.

The $text operator is the primary way to interact with these indexes. The $search field takes a string of terms. By default, terms are treated as OR conditions. To perform an AND search, prefix terms with a space. To exclude terms, prefix them with a hyphen (-).

Consider searching for "organic AND t-shirt" but NOT "blue":

db.products.find( { $text: { $search: "organic t-shirt -blue" } } )

Beyond simple term matching, text search indexes support relevance scoring. You can sort results by their relevance to the search query using $meta: "textScore".

db.products.find(
  { $text: { $search: "breathable t-shirt" } },
  { score: { $meta: "textScore" } }
).sort( { score: { $meta: "textScore" } } )

This query would return documents containing "breathable" and "t-shirt", with the most relevant ones appearing first. The scoring mechanism considers factors like term frequency within a document and inverse document frequency across the collection.

One crucial aspect of text indexes is how they handle multiple fields. When you index multiple fields for text search, MongoDB essentially creates a single, unified index for all those fields. The $search query then operates against this combined index. This means that a search term like "wireless" will match documents where "wireless" appears in any of the indexed fields (name, description, or tags in our example). You can weight fields to influence relevance scoring, making matches in certain fields more impactful than others. For example, to give more weight to matches in the name field:

db.products.createIndex( { name: "text", description: "text", tags: "text" }, { weights: { name: 10, description: 5, tags: 1 } } )

Here, a match in the name field will contribute 10 times more to the score than a match in the tags field. The default weight for all fields is 1.

The most surprising thing about MongoDB’s text search is its integration with the aggregation framework. You can use $text within $match stages, allowing you to combine full-text search with complex data transformations, groupings, and other analytical operations. This means you don’t have to sacrifice analytical power for search capability.

The next logical step is to explore how to perform phrase searches and proximity searches within text indexes.

Want structured learning?

Take the full Mongodb course →