> For the complete MongoDB documentation index, see www.mongodb.com/docs/llms.txt

# MongoDB Search

## Overview

In this guide you can learn how to use the `Search` builder to build a `$search` aggregation pipeline stage with the MongoDB .NET/C# Driver.

To learn more about the `$search` pipeline stage, see [$search.](https://www.mongodb.com/docs/manual/reference/operator/aggregation/search/)

**Note: Atlas and Community Edition Version Requirements**

The `$search` aggregation-pipeline operator is available only for collections hosted on [MongoDB Atlas](https://www.mongodb.com/docs/atlas/) clusters running MongoDB v4.2 or later, or on [MongoDB Community Edition](https://www.mongodb.com/docs/manual/installation/) clusters running MongoDB v8.2 or later. Collections must be covered by a [MongoDB Search index](https://www.mongodb.com/docs/atlas/reference/atlas-search/index-definitions/). To learn more about the required setup and the functionality of this operator, see the [MongoDB Search](https://www.mongodb.com/docs/atlas/atlas-search/) documentation.

### Sample Data

The examples in this guide use the `movies` collection from the `sample_mflix` database. Documents in this collection contain information about films, including their title, plot, genre, and ratings. The following `Movie` class models the documents in this collection:

```csharp
[BsonIgnoreExtraElements]
public class Movie
{
    [BsonId]
    public ObjectId Id { get; set; }
    public string Title { get; set; } = null!;
    public string Plot { get; set; } = null!;
    public string[] Genres { get; set; } = null!;
    public int Year { get; set; }
    public string Rated { get; set; } = null!;
    public Imdb Imdb { get; set; } = null!;
    [BsonElement("plot_embedding")]
    public float[] PlotEmbedding { get; set; } = null!;
    public double Score { get; set; }
    [BsonElement("scoreDetails")]
    [BsonIgnoreIfNull]
    public SearchScoreDetails ScoreDetails { get; set; } = null!;
    [BsonElement("paginationToken")]
    public string PaginationToken { get; set; } = null!;
}

```

The `Movie` class references the following `Imdb` class, which models the nested `imdb` field in each document:

```csharp
[BsonIgnoreExtraElements]
public class Imdb
{
    public double Rating { get; set; }
    public int Votes { get; set; }
    public int Id { get; set; }
}

```

**Note: Camel-Case Field Names in Sample Data**

The documents in the `movies` collection use the camel-case naming convention. The examples in this guide use a `ConventionPack` to deserialize the fields in the collection into Pascal case and map them to the properties in the `Movie` class.

To learn more about custom serialization, see [Custom Serialization.](https://www.mongodb.com/docs/drivers/csharp/current/serialization/poco.md#std-label-csharp-custom-serialization)

Some examples in this guide use additional collections and model classes, which the relevant sections introduce. All collections are from the [sample datasets](https://www.mongodb.com/docs/atlas/sample-data/) provided by Atlas. See [Get Started with the .NET/C# Driver](https://www.mongodb.com/docs/drivers/csharp/current/get-started.md#std-label-csharp-get-started) to learn how to create a free MongoDB cluster and load this sample data.

**Note: Inconsistent Field Types in Sample Data**

Some documents in the `movies` collection store the `imdb.rating` and `imdb.votes` fields as strings instead of numbers. If you define these fields as `double` or `int` in your model class, the driver throws a `FormatException` when deserializing those documents.

To handle documents with mixed field types, implement a custom serializer that accepts multiple BSON types and apply it with the `[BsonSerializer]` attribute on the affected properties:

```csharp
[BsonIgnoreExtraElements]
public class Imdb
{
    [BsonSerializer(typeof(FlexibleDoubleSerializer))]
    public double Rating { get; set; }

    [BsonSerializer(typeof(FlexibleInt32Serializer))]
    public int Votes { get; set; }

    public int Id { get; set; }
}

```

To learn how to implement a custom serializer such as `FlexibleDoubleSerializer`, see [Custom Serializers.](https://www.mongodb.com/docs/drivers/csharp/current/serialization.md#std-label-csharp-custom-serializer)

## Create a MongoDB Search Index

Before you can perform a search on an Atlas collection, you must first create a **MongoDB Search index** on the collection. A MongoDB Search index is a data structure that categorizes data in a searchable format.

To learn how to create a MongoDB Search Index see the [Create a MongoDB Search Index](https://www.mongodb.com/docs/atlas/atlas-search/create-index/) guide.

## MongoDB Search Operators and Collectors

The `Search` class contains methods you can use to perform `$search` operations. For a full list of available `$search` operators and collectors, see the [Operators and Collectors](https://www.mongodb.com/docs/atlas/atlas-search/operators-and-collectors/) Atlas guide.

### Autocomplete

Use the `Autocomplete()` method to search for a word or phrase that contains a sequence of characters from an incomplete input string.

The following example performs an autocomplete query on the `title` field for text that starts with the string `"Gravity"`:

```csharp
var result = moviesCollection.Aggregate()
    .Search(Builders<Movie>.Search.Autocomplete(m => m.Title, "Gravity"), indexName: "movietitles")
    .ToList();

```

**Output:**

```json
...
{ "_id" : ObjectId("..."), "title" : "Gravity", "plot" : "...", "genres" : ["Drama", "Sci-Fi", "Thriller"], "year" : 2013, "rated" : "PG-13", "imdb" : { "rating" : 7.7, "votes" : "...", "id" : "..." } }
...
```

To learn more about the `autocomplete` operator, see the [autocomplete](https://www.mongodb.com/docs/atlas/atlas-search/autocomplete/) Atlas guide.

**Note: Index for Autocomplete Queries**

You must create a MongoDB Search index that supports autocompletion to successfully perform autocomplete queries. To learn more, see [How to Index Fields for Autocompletion](https://www.mongodb.com/docs/atlas/atlas-search/field-types/autocomplete-type/) in the Atlas documentation.

After you create the MongoDB Search index, you must pass the index name to the `Autocomplete()` method, as shown in the preceding example.

### Compound

Use the `Compound()` method to combine two or more operators into a single search.

The following example searches the `movies` collection for any documents that match all the following criteria:

- The `imdb.rating` field exists on the document

- The `rated` field value is not `"G"`

- The `year` field has a value greater than 2000

```csharp
var result = moviesCollection.Aggregate()
    .Search(Builders<Movie>.Search.Compound()
        .Must(Builders<Movie>.Search.Exists(m => m.Imdb.Rating))
        .MustNot(Builders<Movie>.Search.Equals(m => m.Rated, "G"))
        .Must(Builders<Movie>.Search.Range(m => m.Year, SearchRangeBuilder.Gt(2000))))
    .ToList();

```

**Output:**

```json
...
{ "_id" : ObjectId("..."), "title" : "The Dark Knight", "plot" : "...", "genres" : ["Action", "Crime", "Drama"], "year" : 2008, "rated" : "PG-13", "imdb" : { "rating" : 9.0, "votes" : "...", "id" : "..." } }
{ "_id" : ObjectId("..."), "title" : "Inception", "plot" : "...", "genres" : ["Action", "Adventure", "Sci-Fi"], "year" : 2010, "rated" : "PG-13", "imdb" : { "rating" : 8.8, "votes" : "...", "id" : "..." } }
...
```

To learn more about the `compound` operator, see the [compound](https://www.mongodb.com/docs/atlas/atlas-search/compound/) Atlas guide.

### EmbeddedDocument

Use the `EmbeddedDocument()` method to perform search operations on documents within a field's array value.

**Note: Embedded Document Index Required**

To search on embedded documents, you must create an `embeddedDocument` index on the array field.

To learn how to define an `embeddedDocument` index, see [Define the Index for the embeddedDocument Type](https://www.mongodb.com/docs/atlas/atlas-search/field-types/embedded-documents-type/#define-the-index-for-the-fts-field-type-type) in the Atlas documentation.

The examples in this section use the `restaurants` collection from the `sample_restaurants` database. The following classes model the documents in that collection:

```csharp
[BsonIgnoreExtraElements]
public class Restaurant
{
    [BsonId]
    public ObjectId Id { get; set; }
    public string Name { get; set; } = null!;
    public string Cuisine { get; set; } = null!;
    public string Borough { get; set; } = null!;
    public List<GradeEntry> Grades { get; set; } = null!;
}

```

```csharp
[BsonIgnoreExtraElements]
public class GradeEntry
{
    public string Grade { get; set; } = null!;
    public int? Score { get; set; }
}

```

The following example searches that collection for any restaurants whose `grades` array contains an entry with a `grade` field value of `"A"`:

```csharp
var result = restaurantsCollection.Aggregate()
    .Search(Builders<Restaurant>.Search.EmbeddedDocument(
        r => r.Grades,
        Builders<GradeEntry>.Search.Equals(g => g.Grade, "A")
    ), indexName: "restaurantsembedded").ToList();

```

**Output:**

```json
...
{ "_id" : ObjectId("..."), "name" : "Riviera Caterer", "cuisine" : "American", "borough" : "Brooklyn", "grades" : [{ "grade" : "A", "score" : 5 }, { "grade" : "B", "score" : 23 }] }
...
```

To learn more about the `embeddedDocument` operator, see the [embeddedDocument](https://www.mongodb.com/docs/atlas/atlas-search/embedded-document/) Atlas guide.

The following sections describe additional parameters and operators that you can use to extend embedded document searches.

#### returnScope Parameter

Use the `returnScope` parameter of the `Search()` or `SearchMeta()` method to return embedded documents from an array field as individual results instead of root-level documents. When you specify `returnScope`, MongoDB Search scores, sorts, and counts each embedded document independently.

This parameter accepts a lambda expression that specifies the path to the array field that contains the embedded documents.

To use `returnScope`, you must perform the following steps:

- Index the array field as the `embeddedDocuments` type.

- Set the storedSource option in your index definition to the nested field that you want to retrieve.

- Set `ReturnStoredSource` to `true` in your search options.

The following example retrieves documents from the `restaurants` collection that have a value of `"A"` in their `grades` array. The code passes the `r => r.Grades` expression to the `Search()` method as the `returnScope` parameter, which instructs the driver to return the embedded documents in the `grades` array as individual results.

```csharp
var result = restaurantsCollection.Aggregate()
    .Search(
        Builders<Restaurant>.Search.Equals("grades.grade", "A"),
        r => r.Grades,
        new SearchOptions<Restaurant>
        {
            ReturnStoredSource = true,
            IndexName = "restaurantsembedded"
        })
    .ToList();

```

**Output:**

```json
{ "Grade" : "A", "Score" : 0 }
{ "Grade" : "A", "Score" : 0 }
{ "Grade" : "A", "Score" : 0 }
```

To learn more, see fts-return-scope in the Atlas documentation.

#### HasAncestor

Use the `HasAncestor()` method inside an `EmbeddedDocument()` query to filter on a field at an intermediate ancestor level of nesting. An ancestor field is an `embeddedDocuments` type field that is a parent of the embedded field that you specify in the [returnScope parameter](https://www.mongodb.com/docs/drivers/csharp/current/atlas-search.md#std-label-csharp-embedded-doc-return-scope) but is not the root document.

Pass the following parameters to the `HasAncestor()` method:

| Parameter | Required | Description |
| --- | --- | --- |
| `path` | Yes | The path to the ancestor field |
| `operator` | Yes | The search operator to apply to fields within the ancestor field specified in `path` |
| `score` | No | The score modifier to apply to the search results |

To learn more, see has-ancestor-ref in the Atlas documentation.

#### HasRoot

Use the `HasRoot()` method inside an `EmbeddedDocument()` query to filter on root-level fields when you perform an embedded document search.

Pass the following parameters to the `HasRoot()` method:

| Parameter | Required | Description |
| --- | --- | --- |
| `operator` | Yes | The search operator to apply to root-level fields. |
| `score` | No | The score modifier to apply to the search results. |

The following example retrieves documents from the `restaurants` collection that have at least one `"A"` value in the `grades` array. The query uses the `HasRoot()` method to filter on the root-level `borough` field for `"Manhattan"` values.

```csharp
var result = restaurantsCollection.Aggregate()
    .Search(
        Builders<Restaurant>.Search.EmbeddedDocument<Restaurant>(
            "grades",
            Builders<Restaurant>.Search.Compound()
                .Must(
                    Builders<Restaurant>.Search.HasRoot(
                        Builders<Restaurant>.Search.Equals(r => r.Borough, "Manhattan")),
                    Builders<Restaurant>.Search.Equals("grade", "A"))),
        new SearchOptions<Restaurant>
        {
            IndexName = "restaurantsembedded"
        })
    .ToList();

```

**Output:**

```json
{ "_id" : ..., "Name" : "''U'' Like Chinese Restaurant", "Cuisine" : "Chinese", "Borough" : "Manhattan", "Grades" : [{ "Grade" : "A", "Score" : 12 }, { "Grade" : "A", "Score" : 13 }, { "Grade" : "A", "Score" : 13 }, { "Grade" : "A", "Score" : 13 }, { "Grade" : "A", "Score" : 13 }] }
{ "_id" : ..., "Name" : "'Wichcraft", "Cuisine" : "Sandwiches/Salads/Mixed Buffet", "Borough" : "Manhattan", "Grades" : [{ "Grade" : "Z", "Score" : 18 }, { "Grade" : "A", "Score" : 4 }, { "Grade" : "B", "Score" : 18 }] }
{ "_id" : ..., "Name" : "'Wichcraft", "Cuisine" : "Sandwiches/Salads/Mixed Buffet", "Borough" : "Manhattan", "Grades" : [{ "Grade" : "A", "Score" : 4 }, { "Grade" : "A", "Score" : 9 }, { "Grade" : "A", "Score" : 2 }, { "Grade" : "A", "Score" : 10 }] }
```

To learn more, see has-root-ref in the Atlas documentation.

### Equals

Use the `Equals()` method to check whether a field matches a specified value.

The following example searches the `movies` collection for any documents in which the value of the `year` field is `2000`:

```csharp
var result = moviesCollection.Aggregate()
    .Search(Builders<Movie>.Search.Equals(m => m.Year, 2000))
    .ToList();

```

**Output:**

```json
...
{ "_id" : ObjectId("..."), "title" : "Gladiator", "plot" : "...", "genres" : ["Action", "Adventure", "Drama"], "year" : 2000, "rated" : "R", "imdb" : { "rating" : 8.5, "votes" : "...", "id" : "..." } }
{ "_id" : ObjectId("..."), "title" : "Cast Away", "plot" : "...", "genres" : ["Adventure", "Drama", "Romance"], "year" : 2000, "rated" : "PG-13", "imdb" : { "rating" : 7.8, "votes" : "...", "id" : "..." } }
...
```

To learn more about the `equals` operator, see the [equals](https://www.mongodb.com/docs/atlas/atlas-search/equals/) Atlas guide.

### Exists

Use the `Exists()` method to search for documents in which a specified indexed field name exists. If the specified field exists but isn't indexed, the document isn't included with the result set.

The following example searches the `movies` collection for any documents in which the `imdb.rating` field exists. The search returns all documents in which the `imdb.rating` field is present:

```csharp
var result = moviesCollection.Aggregate()
    .Search(Builders<Movie>.Search.Exists(m => m.Imdb.Rating))
    .ToList();

```

**Output:**

```json
...
{ "_id" : ObjectId("..."), "title" : "The Godfather", "plot" : "...", "genres" : ["Crime", "Drama"], "year" : 1972, "rated" : "R", "imdb" : { "rating" : 9.2, "votes" : "...", "id" : "..." } }
{ "_id" : ObjectId("..."), "title" : "The Shawshank Redemption", "plot" : "...", "genres" : ["Drama"], "year" : 1994, "rated" : "R", "imdb" : { "rating" : 9.3, "votes" : "...", "id" : "..." } }
...
```

To learn more about the `exists` operator, see the [exists](https://www.mongodb.com/docs/atlas/atlas-search/exists/) Atlas guide.

### Facet

Use the `Facet()` method to group results by values or ranges in the specified faceted fields and return the count for each of those groups.

You can use the `Facet()` method with both the `$search` and `$searchMeta` stages. MongoDB recommends using facet with the `$searchMeta` stage to retrieve metadata results only for the query. To retrieve metadata results and query results using the `$search` stage, you must use the `$$SEARCH_META` aggregation variable. To learn more about this variable, see the [SEARCH\_META Aggregation Variable](https://www.mongodb.com/docs/atlas/atlas-search/facet/#std-label-fts-facet-aggregation-variable) Atlas guide.

The following limitations apply:

- You can run facet queries on a single field only. You can't run facet queries on groups of fields.

- You can run facet queries over sharded collections on clusters running MongoDB v6.0 only.

The following example searches the `movies` collection for any documents in which the `year` field has a value greater than or equal to `2000`. The query uses the `Facet()` method to process the input documents, with a maximum number of `100` facet categories to return in the results based on the `genres` field. The query returns the number of distinct genre categories found:

```csharp
var result = moviesCollection.Aggregate()
    .SearchMeta(
        Builders<Movie>.Search.Facet(
            Builders<Movie>.Search.Range(m => m.Year, SearchRangeBuilder.Gte(2000)),
            Builders<Movie>.SearchFacet.String("genres", m => m.Genres, 100)),
        indexName: "moviesfacetsearch")
    .Single()
    .Facet["genres"].Buckets.Count();

```

**Output:**

```none
23
```

To learn more about the `facet` collector, see the [facet](https://www.mongodb.com/docs/atlas/atlas-search/facet/) Atlas guide.

### GeoShape

Use the `GeoShape()` method to search for documents in relation to a given geometry. When specifying the coordinates to search, longitude must be specified first, followed by latitude. Longitude values can be between `-180` and `180`, inclusive. Latitude values can be between `-90` and `90`, inclusive.

**Note:**

MongoDB Search does not support the following:

- Non-default coordinate reference system (CRS)

- Planar XY coordinate system (2 dimensional)

- Coordinate pairs Point notation (pointFieldName: \[12, 34])

This example uses the `theaters` collection from the `sample_mflix` database. The following classes model the documents in that collection:

```csharp
[BsonIgnoreExtraElements]
public class Theater
{
    [BsonId]
    public ObjectId Id { get; set; }
    public int TheaterId { get; set; }
    public TheaterLocation Location { get; set; } = null!;
}

```

```csharp
[BsonIgnoreExtraElements]
public class TheaterLocation
{
    [BsonElement("geo")]
    public GeoJsonPoint<GeoJson2DGeographicCoordinates> Geo { get; set; } = null!;
}

```

The following example searches that collection for all documents in which the coordinates in the `location.geo` field intersect with a specified polygon in the Minneapolis, MN area:

```csharp
GeoJsonPolygon<GeoJson2DGeographicCoordinates> searchArea = new(new(new(new GeoJson2DGeographicCoordinates[]
{
    new(-93.5, 44.7),
    new(-93.5, 45.0),
    new(-93.0, 45.0),
    new(-93.0, 44.7),
    new(-93.5, 44.7),
})));

var result = theatersCollection.Aggregate()
    .Search(Builders<Theater>.Search.GeoShape(
        t => t.Location.Geo, GeoShapeRelation.Intersects, searchArea),
        indexName: "theatersgeo")
    .ToList();

```

**Output:**

```json
...
{ "_id" : ObjectId("..."), "theaterId" : 1000, "location" : { "geo" : { "type" : "Point", "coordinates" : [-93.24565, 44.85466] } } }
...
```

To learn more about the `geoShape` operator, see the [geoShape](https://www.mongodb.com/docs/atlas/atlas-search/geoShape/) Atlas guide.

### GeoWithin

Use the `GeoWithin()` method to search for documents in which the coordinates of their specified [GeoJSON](https://www.mongodb.com/docs/manual/reference/geojson/) field are within a given geometry. You can search for points that are within a:

- Circle

- Bounding box

- Polygon

When specifying the coordinates to search, longitude must be specified first, followed by latitude. Longitude values can be between `-180` and `180`, inclusive. Latitude values can be between `-90` and `90`, inclusive.

**Note:**

MongoDB Search does not support the following:

- Non-default coordinate reference system (CRS)

- Planar XY coordinate system (2 dimensional)

- Coordinate pairs Point notation (pointFieldName: \[12, 34])

The following example searches the `theaters` collection for all documents in which the coordinates in the `location.geo` field fall within a specified polygon:

```csharp
GeoJsonPolygon<GeoJson2DGeographicCoordinates> searchArea = new(new(new(new GeoJson2DGeographicCoordinates[]
{
    new(-94.0, 44.5),
    new(-94.0, 45.2),
    new(-92.5, 45.2),
    new(-92.5, 44.5),
    new(-94.0, 44.5),
})));

var result = theatersCollection.Aggregate()
    .Search(Builders<Theater>.Search.GeoWithin(t => t.Location.Geo, searchArea),
        indexName: "theatersgeo")
    .ToList();

```

**Output:**

```json
...
{ "_id" : ObjectId("..."), "theaterId" : 1000, "location" : { "geo" : { "type" : "Point", "coordinates" : [-93.24565, 44.85466] } } }
...
```

To learn more about the `geoWithin` operator, see the [geoWithin](https://www.mongodb.com/docs/atlas/atlas-search/geoWithin/) Atlas guide.

### In

Use the `In()` method to search for documents with field values that match a list of specified values.

The following example searches the `movies` collection for documents that have a `genres` array containing either `"Action"` or `"Comedy"`:

```csharp
var result = moviesCollection.Aggregate()
    .Search(Builders<Movie>.Search.In(m => m.Genres, new[] { "Action", "Comedy" }))
    .ToList();

```

**Output:**

```json
...
{ "_id" : ObjectId("..."), "title" : "Home Alone", "plot" : "...", "genres" : ["Comedy", "Family"], "year" : 1990, "rated" : "PG", "imdb" : { "rating" : 7.4, "votes" : "...", "id" : "..." } }
{ "_id" : ObjectId("..."), "title" : "Die Hard", "plot" : "...", "genres" : ["Action", "Thriller"], "year" : 1988, "rated" : "R", "imdb" : { "rating" : 8.2, "votes" : "...", "id" : "..." } }
...
```

### MoreLikeThis

Use the `MoreLikeThis()` method to search for documents that are similar to an input document.

This example uses the following class to specify the input document for the search:

```csharp
public class MovieSearch
{
    public string Plot { get; set; } = null!;
}

```

The following example searches the `movies` collection for documents similar to an object in which the value of the `plot` field is `"time travel"`:

```csharp
var searchDocument = new MovieSearch()
{
    Plot = "time travel",
};

var result = moviesCollection.Aggregate()
    .Search(Builders<Movie>.Search.MoreLikeThis(searchDocument))
    .ToList();

```

**Output:**

```json
...
{ "_id" : ObjectId("..."), "title" : "Thrill Seekers", "plot" : "...", "genres" : ["Action", "Sci-Fi", "Thriller"], "year" : 1999, "rated" : "...", "imdb" : { "rating" : "...", "votes" : "...", "id" : "..." } }
{ "_id" : ObjectId("..."), "title" : "About Time", "plot" : "...", "genres" : ["Drama", "Fantasy", "Romance"], "year" : 2013, "rated" : "R", "imdb" : { "rating" : 7.8, "votes" : "...", "id" : "..." } }
...
```

To learn more about the `moreLikeThis` operator, see the [moreLikeThis](https://www.mongodb.com/docs/atlas/atlas-search/morelikethis/) Atlas guide.

### Near

Use the `Near()` method to search for documents in which a specified field is near a given value. You can perform the search on:

- A number field

- A date field

- A geographic point

The following example searches the `movies` collection for documents in which the value of the `imdb.rating` field is near `8.5`. The documents are returned in order based on how close the value is to `8.5`:

```csharp
var result = moviesCollection.Aggregate()
    .Search(Builders<Movie>.Search.Near(m => m.Imdb.Rating, 8.5, 1))
    .ToList();

```

**Output:**

```json
...
{ "_id" : ObjectId("..."), "title" : "The Dark Knight", "plot" : "...", "genres" : ["Action", "Crime", "Drama"], "year" : 2008, "rated" : "PG-13", "imdb" : { "rating" : 9.0, "votes" : "...", "id" : "..." } }
{ "_id" : ObjectId("..."), "title" : "The Godfather", "plot" : "...", "genres" : ["Crime", "Drama"], "year" : 1972, "rated" : "R", "imdb" : { "rating" : 9.2, "votes" : "...", "id" : "..." } }
...
```

To learn more about the `near` operator, see the [near](https://www.mongodb.com/docs/atlas/atlas-search/near/) Atlas guide.

### Phrase

Use the `Phrase()` method to search for documents in which a specified field contains an input string.

The following example searches the `movies` collection for documents in which the `plot` field contains the phrase `"time travel"`:

```csharp
var result = moviesCollection.Aggregate()
    .Search(Builders<Movie>.Search.Phrase(m => m.Plot, "time travel"))
    .ToList();

```

**Output:**

```json
...
{ "_id" : ObjectId("..."), "title" : "The Time Traveler's Wife", "plot" : "...", "genres" : ["Drama", "Fantasy", "Romance"], "year" : 2009, "rated" : "PG-13", "imdb" : { "rating" : 7.1, "votes" : "...", "id" : "..." } }
{ "_id" : ObjectId("..."), "title" : "Safety Not Guaranteed", "plot" : "...", "genres" : ["Comedy", "Drama", "Romance"], "year" : 2012, "rated" : "R", "imdb" : { "rating" : 7, "votes" : "...", "id" : "..." } }
...
```

You can also search the collection for documents that contain either `"time travel"` or `"space adventure"` in the `plot` field:

```csharp
var result = moviesCollection.Aggregate()
    .Search(Builders<Movie>.Search.Phrase(m => m.Plot, new List<string>() { "time travel", "space adventure" }))
    .ToList();

```

**Output:**

```json
...
{ "_id" : ObjectId("..."), "title" : "The Time Traveler's Wife", "plot" : "...", "genres" : ["Drama", "Fantasy", "Romance"], "year" : 2009, "rated" : "PG-13", "imdb" : { "rating" : 7.1, "votes" : "...", "id" : "..." } }
{ "_id" : ObjectId("..."), "title" : "Safety Not Guaranteed", "plot" : "...", "genres" : ["Comedy", "Drama", "Romance"], "year" : 2012, "rated" : "R", "imdb" : { "rating" : 7, "votes" : "...", "id" : "..." } }
...
```

To learn more about the `phrase` operator, see the [phrase](https://www.mongodb.com/docs/atlas/atlas-search/phrase/) Atlas guide.

### QueryString

Use the `QueryString()` method to search for documents using a string with the following operators and delimiters:

- `AND`

- `OR`

- `NOT`

- `()`

The following example searches the `movies` collection for documents in which the value of the `plot` field matches each of the following criteria:

- Contains the string `"time"` *or* the string `"space"`

- Does not contain the string `"comedy"`

```csharp
var result = moviesCollection.Aggregate()
    .Search(Builders<Movie>.Search.QueryString(m => m.Plot, "(time OR space) AND NOT comedy"))
    .ToList();

```

**Output:**

```json
...
{ "_id" : ObjectId("..."), "title" : "Interstellar", "plot" : "...", "genres" : ["Adventure", "Drama", "Sci-Fi"], "year" : 2014, "rated" : "PG-13", "imdb" : { "rating" : 8.7, "votes" : "...", "id" : "..." } }
{ "_id" : ObjectId("..."), "title" : "Tomorrowland", "plot" : "...", "genres" : ["Action", "Adventure", "Family"], "year" : 2015, "rated" : "PG", "imdb" : { "rating" : 6.6, "votes" : "...", "id" : "..." } }
...
```

To learn more about the `queryString` operator, see the [queryString](https://www.mongodb.com/docs/atlas/atlas-search/queryString/) Atlas guide.

### Range

Use the `Range()` method to search for documents in which the value of a specified field falls within a given numeric, date, or string range.

The following example searches the `movies` collection for all documents with a `year` value greater than `2000` and less than `2010`:

```csharp
var result = moviesCollection.Aggregate()
    .Search(Builders<Movie>.Search
    .Range(m => m.Year, SearchRangeBuilder.Gt(2000).Lt(2010)))
    .ToList();

```

**Output:**

```json
...
{ "_id" : ObjectId("..."), "title" : "The Dark Knight", "plot" : "...", "genres" : ["Action", "Crime", "Drama"], "year" : 2008, "rated" : "PG-13", "imdb" : { "rating" : 9.0, "votes" : "...", "id" : "..." } }
{ "_id" : ObjectId("..."), "title" : "The Departed", "plot" : "...", "genres" : ["Crime", "Drama", "Thriller"], "year" : 2006, "rated" : "R", "imdb" : { "rating" : 8.5, "votes" : "...", "id" : "..." } }
...
```

To search for documents in which the value of a specified field is within a range of strings, you must first create a [token index](https://www.mongodb.com/docs/atlas/atlas-search/field-types/token-type/) on the field. After you create the index, you can search for documents based on a range of strings. The following example returns documents in which the `title` field value falls between `"A"` and `"G"`, compared in [lexicographic order:](https://en.wikipedia.org/wiki/Lexicographic_order)

```csharp
var result = moviesCollection.Aggregate()
     .Search(Builders<Movie>.Search
     .Range(m => m.Title, SearchRangeV2Builder.Gte("A").Lte("G")))
     .ToList();

```

**Output:**

```json
...
{ "_id" : ObjectId("..."), "title" : "Apollo 13", "plot" : "...", "genres" : ["Adventure", "Drama", "History"], "year" : 1995, "rated" : "PG", "imdb" : { "rating" : 7.6, "votes" : "...", "id" : "..." } }
{ "_id" : ObjectId("..."), "title" : "Braveheart", "plot" : "...", "genres" : ["Biography", "Drama", "History"], "year" : 1995, "rated" : "R", "imdb" : { "rating" : 8.3, "votes" : "...", "id" : "..." } }
...
```

To learn more about the `range` operator, see the [range](https://www.mongodb.com/docs/atlas/atlas-search/range/) Atlas guide.

### Regex

Use the `Regex()` method to search for documents using a regular expression.

The following example searches the `movies` collection for documents in which the value of the `title` field contains exactly six letters:

```csharp
var regex = "[A-Za-z]{6}";

var result = moviesCollection.Aggregate()
    .Search(Builders<Movie>.Search.Regex(m => m.Title, regex,
        allowAnalyzedField: true))
    .ToList();

```

**Output:**

```json
...
{ "_id" : ObjectId("..."), "title" : "Gandhi", "plot" : "...", "genres" : ["Biography", "Drama", "History"], "year" : 1982, "rated" : "PG", "imdb" : { "rating" : 8.0, "votes" : "...", "id" : "..." } }
{ "_id" : ObjectId("..."), "title" : "Batman", "plot" : "...", "genres" : ["Action", "Adventure"], "year" : 1989, "rated" : "PG-13", "imdb" : { "rating" : 7.5, "votes" : "...", "id" : "..." } }
...
```

**Note: Running Regex on Analyzed Fields**

By default, the `regex` operator can't run on an analyzed field. You can allow it to run on an analyzed field by setting the `allowAnalyzedField` option to true, as follows:

```csharp
var result = moviesCollection.Aggregate()
    .Search(Builders<Movie>.Search.Regex(m => m.Title, regex,
        allowAnalyzedField: true))
    .ToList();

```

Setting the `allowAnalyzedField` option to `true` may lead to unexpected search results. To learn more, see [Behavior](https://www.mongodb.com/docs/atlas/atlas-search/regex/#behavior) in the Atlas `regex` guide.

To learn more about the `regex` operator, see the [regex](https://www.mongodb.com/docs/atlas/atlas-search/regex/) Atlas guide.

### Span

Use the `Span()` method to search for text search matches within regions of a field. You can use this method to find strings which are near each other to specified degrees of precision.

**Note: Span Operator Performance**

The `span` operator is more computationally intensive than other operators because queries must keep track of positional information.

The following example searches the `movies` collection for documents in which the value of the `plot` field contains the strings `"time"` and `"travel"` within one word of each other:

```csharp
var searchTerms = new[]
{
    Builders<Movie>.SearchSpan.Term(m => m.Plot, "time"),
    Builders<Movie>.SearchSpan.Term(m => m.Plot, "travel")
};

var result = moviesCollection.Aggregate()
    .Search(Builders<Movie>.Search.Span(Builders<Movie>.SearchSpan.Near(searchTerms, 1)))
    .ToList();

```

**Output:**

```json
...
{ "_id" : ObjectId("..."), "title" : "The Time Traveler's Wife", "plot" : "...", "genres" : ["Drama", "Fantasy", "Romance"], "year" : 2009, "rated" : "PG-13", "imdb" : { "rating" : 7.1, "votes" : "...", "id" : "..." } }
{ "_id" : ObjectId("..."), "title" : "About Time", "plot" : "...", "genres" : ["Drama", "Fantasy", "Romance"], "year" : 2013, "rated" : "R", "imdb" : { "rating" : 7.8, "votes" : "...", "id" : "..." } }
...
```

To learn more about the `span` operator, see the [span](https://www.mongodb.com/docs/atlas/atlas-search/span/) Atlas guide.

### Text

Use the `Text()` method to search a document for a given string or array of strings. If there are multiple terms in a given string, MongoDB Search also looks for a match for each term in the string separately.

The following example searches the `movies` collection for documents in which the value of the `plot` field contains the string `"secret agent"`:

```csharp
var result = moviesCollection.Aggregate()
    .Search(Builders<Movie>.Search.Text(m => m.Plot, "secret agent"))
    .ToList();

```

**Output:**

```json
...
{ "_id" : ObjectId("..."), "title" : "Spy Kids", "plot" : "...", "genres" : ["Action", "Adventure", "Comedy"], "year" : 2001, "rated" : "PG", "imdb" : { "rating" : 5.4, "votes" : "...", "id" : "..." } }
{ "_id" : ObjectId("..."), "title" : "The Spy Who Loved Me", "plot" : "...", "genres" : ["Action", "Adventure", "Thriller"], "year" : 1977, "rated" : "PG", "imdb" : { "rating" : 7.1, "votes" : "...", "id" : "..." } }
...
```

**Tip: Multi-Term Search Behavior**

If your search string contains multiple terms, the method also looks for a match for each term in the string separately.

To learn more about the `text` operator, see the [text](https://www.mongodb.com/docs/atlas/atlas-search/text/) Atlas guide.

### Wildcard

Use the `Wildcard()` method to search for documents using special characters in your search string that can match any character. You can use the following characters in your search:

| Character | Description |
| --- | --- |
| `?` | Matches any single character |
| `*` | Matches 0 or more characters |
| `\` | Escape character |

The following example searches for documents in which the value of the `title` field contains the string `"Amer"` followed by any other characters:

```csharp
var result = moviesCollection.Aggregate()
    .Search(Builders<Movie>.Search.Wildcard(m => m.Title, "Amer*", allowAnalyzedField: true))
    .ToList();

```

**Output:**

```json
...
{ "_id" : ObjectId("..."), "title" : "American Beauty", "plot" : "...", "genres" : ["Drama"], "year" : 1999, "rated" : "R", "imdb" : { "rating" : 8.4, "votes" : "...", "id" : "..." } }
{ "_id" : ObjectId("..."), "title" : "American Gangster", "plot" : "...", "genres" : ["Biography", "Crime", "Drama"], "year" : 2007, "rated" : "R", "imdb" : { "rating" : 7.8, "votes" : "...", "id" : "..." } }
...
```

**Note: Running Wildcard on Analyzed Fields**

By default, the `wildcard` operator can't run on an analyzed field. You can allow it to run on an analyzed field by setting `allowAnalyzedField` option to true, as follows:

```csharp
var result = moviesCollection.Aggregate()
    .Search(Builders<Movie>.Search.Wildcard(m => m.Title, "Amer*", allowAnalyzedField: true))
    .ToList();

```

Setting the `allowAnalyzedField` option to true may lead to unexpected search results. To learn more, see [wildcard Behavior.](https://www.mongodb.com/docs/atlas/atlas-search/wildcard/#behavior)

To learn more about the `wildcard` operator, see the [wildcard](https://www.mongodb.com/docs/atlas/atlas-search/wildcard/) Atlas guide.

## Specify a Search Path

You can specify the path to the field or fields to search by using the `SearchPathDefinitionBuilder` class. Use `Builders<TDocument>.SearchPath` to access a `SearchPathDefinitionBuilder` instance and call one of its methods to specify the search path. The following sections describe the available methods.

**Tip: Search Paths**

To learn more about search paths, see [Construct a Query Path](https://www.mongodb.com/docs/atlas/atlas-search/path-construction/) in the Atlas documentation.

### Single Field

Use the `Single()` method to specify one field as the search path. The following examples show three ways to specify the field: by using a lambda expression with a typed model, by passing a string field name such as a `fieldName` variable or method parameter whose value is known at runtime, or by using an untyped document.

**Note:**

The field that you pass to the `Single()` method must be included in the [search index definition](https://www.mongodb.com/docs/atlas/atlas-search/create-index/). If the field isn't included, MongoDB Server returns an empty result set without returning an error.

#### Lambda Expression

Use a lambda expression when you're working with a typed model and you know the field name at compile time. This form provides compile-time type checking.

The following example searches the `plot` field for documents that contain the text `"secret agent"`:

```csharp
var result = moviesCollection.Aggregate()
    .Search(Builders<Movie>.Search.Text(
        Builders<Movie>.SearchPath.Single(m => m.Plot), "secret agent"))
    .ToList();

```

**Output:**

```json
[
  "...",
  { "_id" : ObjectId("..."), "title" : "Spy Kids", "plot" : "...", "genres" : ["Action", "Adventure", "Comedy"], "year" : 2001, "rated" : "PG", "imdb" : { "rating" : 5.4, "votes" : "...", "id" : "..." } },
  "...",
  { "_id" : ObjectId("..."), "title" : "The Spy Who Loved Me", "plot" : "...", "genres" : ["Action", "Adventure", "Thriller"], "year" : 1977, "rated" : "PG", "imdb" : { "rating" : 7.1, "votes" : "...", "id" : "..." } },
  "..."
]

```

#### String Field Name

Use a `FieldDefinition<TDocument>` when you're working with a typed model but you don't know the field name at compile time. Consider using this form if you're retrieving the field name from user input or a configuration file.

The following example assigns the field name to a `FieldDefinition<Movie>` variable and passes it to `Single()`:

```csharp
FieldDefinition<Movie> runtimeField = fieldName;
var result = moviesCollection.Aggregate()
    .Search(Builders<Movie>.Search.Text(
        Builders<Movie>.SearchPath.Single(runtimeField), "secret agent"))
    .ToList();

```

**Output:**

```json
[
  "...",
  { "_id" : ObjectId("..."), "title" : "Spy Kids", "plot" : "...", "genres" : ["Action", "Adventure", "Comedy"], "year" : 2001, "rated" : "PG", "imdb" : { "rating" : 5.4, "votes" : "...", "id" : "..." } },
  "...",
  { "_id" : ObjectId("..."), "title" : "The Spy Who Loved Me", "plot" : "...", "genres" : ["Action", "Adventure", "Thriller"], "year" : 1977, "rated" : "PG", "imdb" : { "rating" : 7.1, "votes" : "...", "id" : "..." } },
  "..."
]

```

#### BsonDocument

You must also specify the field name as a string when you're working with `BsonDocument` objects instead of a typed model.

The following example searches an untyped collection for documents in the `plot` field that contain the text `"secret agent"`:

```csharp
var result = moviesCollectionBson.Aggregate()
    .Search(Builders<BsonDocument>.Search.Text(
        Builders<BsonDocument>.SearchPath.Single("plot"), "secret agent"))
    .ToList();

```

**Output:**

```json
[
  "...",
  { "_id" : ObjectId("..."), "title" : "Spy Kids", "plot" : "...", "...": "..." },
  "...",
  { "_id" : ObjectId("..."), "title" : "The Spy Who Loved Me", "plot" : "...", "...": "..." },
  "..."
]

```

### Multiple Fields

Use the `Multi()` method to specify the search path for multiple fields. The result set includes documents that match on any of the specified fields.

**Note:**

You must include all fields that you pass to the `Multi()` method in the [search index definition](https://www.mongodb.com/docs/atlas/atlas-search/create-index/). If you pass a field that isn't included, MongoDB Server silently excludes it from the search.

The following example searches for the phrase `"time travel"` in either the `plot` or the `title` field:

```csharp
var result = moviesCollection.Aggregate().Search(
    Builders<Movie>.Search.Phrase(Builders<Movie>.SearchPath
    .Multi(m => m.Plot, m => m.Title), "time travel"), indexName: "moviesmulti")
    .ToList();

```

**Output:**

```json
[
  "...",
  { "title" : "Safety Not Guaranteed", "year" : 2012, "rated" : "R" },
  { "title" : "The Time Traveler's Wife", "year" : 2009, "rated" : "PG-13" },
  "..."
]

```

### Analyzer

Analyzers process text into searchable tokens by applying operations such as lowercasing. MongoDB Server applies an analyzer when indexing a field and again when running a query against that field. If you specify the [multi](https://www.mongodb.com/docs/atlas/atlas-search/analyzers/multi/) option when you create a search index, MongoDB Server also stores a second set of tokens produced by an alternate analyzer.

You can use the `Analyzer()` method to run a query against the tokens produced by a `multi` analyzer instead of the tokens produced by the field's default analyzer. The name you pass to `Analyzer()` must be the key name of the `multi` block in your index definition, not the name of the underlying analyzer.

The following example uses a `multi` analyzer named `"lucene"` to search the `title` field for documents that contain the text `"gravity"`:

```csharp
var result = moviesCollection.Aggregate()
    .Search(Builders<Movie>.Search.Text(
        Builders<Movie>.SearchPath.Analyzer(m => m.Title, "lucene"),
        "gravity"), indexName: "moviesanalyzer")
    .ToList();

```

**Output:**

```json
[
  "...",
  { "title" : "Gravity", "year" : 2013, "rated" : "PG-13" },
  "..."
]

```

**Tip: Analyzers**

To learn more about analyzers, see [Analyzers](https://www.mongodb.com/docs/atlas/atlas-search/analyzers/) in the Atlas documentation.

### Wildcard Path

Use the `Wildcard()` method to specify a search path that uses wildcard characters to match field names. You can use the `*` character in the field name to match any sequence of characters.

MongoDB Server searches only fields that meet the following conditions:

- The field must be indexed.

- The field name must match the specified pattern.

- The field's data type must match the search operator. For example, a `Text()` query searches only string fields.

The following example searches all fields whose names start with `"p"` for documents that contain the text `"secret agent"`:

```csharp
var result = moviesCollection.Aggregate()
    .Search(Builders<Movie>.Search.Text(
        Builders<Movie>.SearchPath.Wildcard("p*"), "secret agent"))
    .ToList();

```

**Output:**

```json
[
  "...",
  { "_id" : ObjectId("..."), "title" : "Spy Kids", "plot" : "...", "genres" : ["Action", "Adventure", "Comedy"], "year" : 2001, "rated" : "PG", "imdb" : { "rating" : 5.4, "votes" : "...", "id" : "..." } },
  "...",
  { "_id" : ObjectId("..."), "title" : "The Spy Who Loved Me", "plot" : "...", "genres" : ["Action", "Adventure", "Thriller"], "year" : 1977, "rated" : "PG", "imdb" : { "rating" : 7.1, "votes" : "...", "id" : "..." } },
  "..."
]

```

**Note: Wildcard Performance**

Broad patterns, such as `"*"`, match all indexed fields and might affect query performance on large indexes.

To learn more about wildcard paths, see [Construct a Query Path](https://www.mongodb.com/docs/atlas/atlas-search/path-construction/) in the Atlas documentation.

## Score Documents

MongoDB Server assigns a relevance score to every document that it returns from a MongoDB Search query. The query returns the documents in order from highest score to lowest. To learn more about how scores are assigned, see the [score](https://www.mongodb.com/docs/atlas/atlas-search/scoring/) Atlas guide.

The score assigned to a returned document is part of the document's metadata. You can include each returned document's score along with the result set by using a `$project` stage in your aggregation pipeline.

The following example searches the `movies` collection for documents in which the value of the `title` field contains exactly six letters and uses a `$project` stage to add a field named `score` to the returned documents:

```csharp
var regex = "[A-Za-z]{6}";

var result = moviesCollection.Aggregate()
    .Search(Builders<Movie>.Search.Regex(m => m.Title, regex, allowAnalyzedField: true), indexName: "moviescore")
    .Project<Movie>(Builders<Movie>.Projection
    .Include(m => m.Id)
    .Include(m => m.Title)
    .Include(m => m.Plot)
    .MetaSearchScore(m => m.Score))
    .ToList();

```

**Output:**

```json
...
{ "_id" : ObjectId("..."), "title" : "Gandhi", "plot" : "...", "score" : 1.0 }
{ "_id" : ObjectId("..."), "title" : "Batman", "plot" : "...", "score" : 1.0 }
...
```

## Modify MongoDB Search Behavior

You can modify the behavior of the `Search()` method by passing a `SearchOptions` object as a parameter.

The `SearchOptions` class contains the following properties:

| Property | Description |
| --- | --- |
| `CountOptions` | The options for counting the search results. **Data type**: [SearchCountOptions](https://mongodb.github.io/mongo-csharp-driver/3.12.0/api/MongoDB.Driver/MongoDB.Driver.Search.SearchCountOptions.html)**Default**: `null` |
| `Highlight` | The options for displaying search terms in their original context. **Data type**: [SearchHighlightOptions<TDocument>](https://mongodb.github.io/mongo-csharp-driver/3.12.0/api/MongoDB.Driver/MongoDB.Driver.Search.SearchHighlightOptions-1.html)**Default**: `null` |
| `IndexName` | The index to use for the search. **Data type**: `string`**Default**: `null` |
| `ReturnStoredSource` | A flag that specifies whether to perform a full document lookup on the database or to return only stored source fields directly from MongoDB Search. **Data type**: `boolean`**Default**: `false` |
| `ScoreDetails` | A flag that specifies whether to return detailed information about the score for each document in the results. **Data type**: `boolean`**Default**: `false` |
| `SearchAfter` | The starting point for pagination. When set, the search retrieves documents starting immediately after the specified reference point. **Data type**: `string`**Default**: `null` |
| `SearchBefore` | The end point for pagination. When set, the search retrieves documents starting immediately before the specified reference point. **Data type**: `string`**Default**: `null` |
| `Sort` | The sorting criteria to apply to the results. **Data type**: [SortDefinition<TDocument>](https://mongodb.github.io/mongo-csharp-driver/3.12.0/api/MongoDB.Driver/MongoDB.Driver.SortDefinition-1.html)**Default**: `null` |
| `Tracking` | The options for tracking search terms. **Data type**: [SearchTrackingOptions](https://mongodb.github.io/mongo-csharp-driver/3.12.0/api/MongoDB.Driver/MongoDB.Driver.Search.SearchTrackingOptions.html)**Default**: `null` |

### SearchAfter Example

The following example paginates the results of a MongoDB Search operation by performing the following actions:

- Defines a projection that uses the `MetaSearchSequenceToken()` builder method, which specifies a `PaginationToken` to contain the point of reference

- Creates a `SearchOptions` instance and sets the index and sort criteria to use

- Runs an initial search to find documents that have a `plot` field value containing the text `"time travel"`, applying the projection and options to the operation

- Sets the `SearchAfter` property of the same `SearchOptions` instance to instruct the next search to begin after the base search's first result

- Runs another search operation that has the same matching criteria and applies the search options to paginate the results

```csharp
var projection = Builders<Movie>.Projection
    .Include(x => x.Title)
    .MetaSearchSequenceToken(x => x.PaginationToken);

var searchDefinition = Builders<Movie>.Search.Text(m => m.Plot, "time travel");
var searchOptions = new SearchOptions<Movie>
{ IndexName = "default", Sort = Builders<Movie>.Sort.Ascending(m => m.Id) };

// Runs the base search operation
var baseSearchResults = moviesCollection.Aggregate()
    .Search(searchDefinition, searchOptions)
    .Project<Movie>(projection)
    .ToList();

if (baseSearchResults.Count == 0)
    return baseSearchResults;

// Sets the starting point for the next search
searchOptions.SearchAfter = baseSearchResults[0].PaginationToken;

var result = moviesCollection.Aggregate()
    .Search(searchDefinition, searchOptions)
    .Project<Movie>(projection)
    .ToList();

```

**Output:**

```json
...
{ "_id" : ObjectId("..."), "title" : "About Time", "plot" : "...", "genres" : ["Comedy", "Drama", "Romance"], "year" : 2013, "rated" : "R", "imdb" : { "rating" : 7.8, "votes" : "...", "id" : "..." } }
...
```

**Tip: Pagination Documentation**

To learn more about MongoDB Search pagination, see [Paginate the Results](https://www.mongodb.com/docs/atlas/atlas-search/paginate-results/) in the Atlas documentation.
