Docs Menu

Docs HomeDevelop ApplicationsMongoDB DriversNode.js

Search Text

On this page

  • Overview
  • Examples
  • Query for Words
  • Query By Phrase
  • Query with Negations
  • Sort by Relevance

Text search, using the $text query operator, lets you search string type fields in your collection for words or phrases. This operator performs a logical OR on each term separated by a space in the search string. You can also specify additional options to the operator to handle case sensitivity, word stemming (e.g. plural forms, tense) and stop words for a supported language. This is particularly useful for unstructured text such as transcripts, essays, or web pages.

The $text query operator requires that you specify the search field in a text index on your collection. See the examples below for sample code for creating a text index and using the $text query operator.

Note

Atlas Search makes it easy to build fast, relevance-based search capabilities on top of your MongoDB data. Try it today on MongoDB Atlas, our fully managed database as a service.

The following examples use sample data from the movies collection in the sample_mflix database. In order to enable text searches on the title field, create a text index by using the following command:

db.movies.createIndex({ title: "text" });

We use a single field text index for the examples in this guide, but you can create a compound text index that broadens your text queries to multiple fields. The following command creates a text index on two fields in the movies collection:

db.movies.createIndex({ title: "text", plot: "text" });

Tip

Specify Field Weights in a Text Index

When creating a compound text index, you can specify a weight option to prioritize certain text fields in your index. When you execute a text search, the field weights influence how MongoDB calculates the text search score for each matching document.

To learn more about specifying field weights when creating a text index, see the Text Indexes section in the Indexes guide.

You can only create one text index per collection. Every text search queries all the fields specified in that index for matches.

To learn more about text indexes, see Text Indexes in the Server manual.

This example queries for Star Trek movies by searching for titles containing the word "trek". If you want to query using multiple words, separate your words with spaces to query for documents that match any of the search terms (logical OR).

const query = { $text: { $search: "trek" } };
// Return only the `title` of each matched document
const projection = {
_id: 0,
title: 1,
};
// find documents based on our query and projection
const cursor = movies.find(query).project(projection);

This operation returns the following documents:

{ title: 'Trek Nation' }
{ title: 'Star Trek' }
{ title: 'Star Trek Into Darkness' }
{ title: 'Star Trek: Nemesis' }
{ title: 'Star Trek: Insurrection' }
{ title: 'Star Trek: Generations' }
{ title: 'Star Trek: First Contact' }
{ title: 'Star Trek: The Motion Picture' }
{ title: 'Star Trek VI: The Undiscovered Country' }
{ title: 'Star Trek V: The Final Frontier' }
{ title: 'Star Trek IV: The Voyage Home' }
{ title: 'Star Trek III: The Search for Spock' }
{ title: 'Star Trek II: The Wrath of Khan' }

Success! The query found every document in the movies collection with a title including the word "trek". Unfortunately, the search included one unintended item: "Trek Nation," which is a movie about Star Trek and not part of the Star Trek movie series. To solve this, we can query with a more specific phrase.

To make your query more specific, try using the phrase "star trek" instead of just the word "trek". To search by phrase, surround your multi-word phrase with escaped quotes (\"<term>\"):

const query = { $text: { $search: "\"star trek\"" } };
// Return only the `title` of each matched document
const projection = {
_id: 0,
title: 1,
};
// find documents based on our query and projection
const cursor = movies.find(query).project(projection);

Querying by the phrase "star trek" instead of just the term "trek" matches the following documents:

{ title: 'Star Trek' }
{ title: 'Star Trek Into Darkness' }
{ title: 'Star Trek: Nemesis' }
{ title: 'Star Trek: Insurrection' }
{ title: 'Star Trek: Generations' }
{ title: 'Star Trek: First Contact' }
{ title: 'Star Trek: The Motion Picture' }
{ title: 'Star Trek VI: The Undiscovered Country' }
{ title: 'Star Trek V: The Final Frontier' }
{ title: 'Star Trek IV: The Voyage Home' }
{ title: 'Star Trek III: The Search for Spock' }
{ title: 'Star Trek II: The Wrath of Khan' }

These results include all movies in the database that contain the phrase "star trek", which in this case results in only fictional Star Trek movies. Unfortunately, though, this query returned "Star Trek Into Darkness", a movie that was not part of the original series of movies. To resolve this issue, we can omit that document with a negation.

To use a negated term, place a negative sign (-) in front of the term you would like to omit from the result set. The query operation omits any documents that contain this term from the search result. Since this query includes two distinct terms, separate them with a space.

const query = { $text: { $search: "\"star trek\" -\"into darkness\"" } };
// Include only the `title` field of each matched document
const projection = {
_id: 0,
title: 1,
};
// find documents based on our query and projection
const cursor = movies.find(query).project(projection);

Querying with the negated term yields the following documents:

{ title: 'Star Trek' }
{ title: 'Star Trek: Nemesis' }
{ title: 'Star Trek: Insurrection' }
{ title: 'Star Trek: Generations' }
{ title: 'Star Trek: First Contact' }
{ title: 'Star Trek: The Motion Picture' }
{ title: 'Star Trek VI: The Undiscovered Country' }
{ title: 'Star Trek V: The Final Frontier' }
{ title: 'Star Trek IV: The Voyage Home' }
{ title: 'Star Trek III: The Search for Spock' }
{ title: 'Star Trek II: The Wrath of Khan' }

Note

Your query operation may return a reference to a cursor that contains matching documents. To learn how to examine data stored in the cursor, see the Cursor Fundamentals page.

Now that the result set reflects the desired results, you can use the text search textScore, accessed using the $meta operator in the query projection, to order the results by relevance:

const query = { $text: { $search: "\"star trek\" -\"into darkness\"" } };
// sort returned documents by descending text relevance score
const sort = { score: { $meta: "textScore" } };
// Include only the `title` and `score` fields in each returned document
const projection = {
_id: 0,
title: 1,
score: { $meta: "textScore" },
};
// find documents based on our query, sort, and projection
const cursor = movies
.find(query)
.sort(sort)
.project(projection);

Querying in this way returns the following documents in the following order. In general, text relevance increases as a string matches more terms and decreases as the unmatched portion of the string lengthens.

{ title: 'Star Trek', score: 1.5 }
{ title: 'Star Trek: Generations', score: 1.3333333333333333 }
{ title: 'Star Trek: Insurrection', score: 1.3333333333333333 }
{ title: 'Star Trek: Nemesis', score: 1.3333333333333333 }
{ title: 'Star Trek: The Motion Picture', score: 1.25 }
{ title: 'Star Trek: First Contact', score: 1.25 }
{ title: 'Star Trek II: The Wrath of Khan', score: 1.2 }
{ title: 'Star Trek III: The Search for Spock', score: 1.2 }
{ title: 'Star Trek IV: The Voyage Home', score: 1.2 }
{ title: 'Star Trek V: The Final Frontier', score: 1.2 }
{ title: 'Star Trek VI: The Undiscovered Country', score: 1.2 }

For more information about the $text operator and its options, see the manual entry.

←  Search GeospatiallyWrite Operations →