
Do you know about MongoDB Text Search? Imagine we are building an app and want users to search by ingredients or dish names (like chocolate or zucchini bread) and get the most relevant results. But wait! We have that information in multiple places, like the recipe title or the ingredients, or tags (like “pasta” on a linguini recipe) and even the directions too! How can we search all that data at once?
MongoDB can do that with built-in text search and relevance scoring … no extra search service or AI 🤖 required.
Setting Up a Text Index for Recipes
Here’s how to define a text index on key fields:
db.recipes.createIndex({
title: "text",
ingredient_text: "text",
directions: "text",
tags: "text"
}, {
weights: {
title: 10,
ingredient_text: 5,
directions: 2,
tags: 3
}
});
This setup boosts matches in the title
and ingredients
, while still including directions
and tags
for broader context. However we have a small issue, our ingredients field is actually an array of objects that look like this:
"ingredients": [
{
"name": "peas",
"quantity": {
"amount": 1,
"unit": "cup"
},
"vegetarian": true
},
{
"name": "water",
"quantity": {
"amount": 8,
"unit": "cup"
},
"vegetarian": true
}
]
This is great for overall usage, but not so great for text searching as MongoDB’s text index doesn’t support nested fields like ingredients.name
directly since it’s an array of objects, not strings.
There are a couple of ways to deal with this problem, but to keep things simple we will add a new field called ingredient_text
that flattens the list of ingredient names for each document using updateMany along with $set
and $map
like so:
db.recipes.updateMany({}, [
{
$set: {
ingredient_text: {
$map: {
input: "$ingredients",
as: "i",
in: "$$i.name"
}
}
}
}
]);
This gives us a simple array like
["milk", "onion", "salt"]
, which MongoDB can index with a text index.
Searching with Relevance
Once indexed, we can use the special $text operator to make searching … and get back results ranked by relevance:
db.recipes.find(
{ $text: { $search: "chocolate zucchini" } },
{ score: { $meta: "textScore" }, title: 1 }
).sort({ score: { $meta: "textScore" } });
Note: We have assigned
textScore
(calculated by MongoDB) to a field called score, so we can then output just thetitle
,score
and_id
in our results.
Now you can search by ingredient, title, tag, or even words that appear in the cooking directions and MongoDB will return the best matches first:
{
_id: '7599a70e-31e8-4ba1-b45c-db7fb286842e',
title: 'Hearty Chocolate Cake',
score: 18.833333333333336
},
{
_id: '5ddb56a1-d182-4276-bbf3-091250f7c7c4',
title: 'Savory Zucchini Bread',
score: 14.476190476190476
}
✨ Want More?
If you need typo tolerance, stemming, synonyms, or autocomplete, check out MongoDB Atlas Search … it builds on this foundation with Lucene-based power.
But for small to medium apps, this native $text
search is fast, easy, and already built in.