# MongoDB Atlas Search with .NET Blazor for Full-Text Search

Imagine being presented with a website with a large amount of data and not being able to search for what you want. Instead, you’re forced to sift through piles of results with no end in sight.

That is, of course, the last thing you want for yourself or your users. So in this tutorial, we’ll see how you can easily implement search with autocomplete in your .NET Blazor application using MongoDB Atlas Search.

Atlas Search is the easiest and fastest way to implement relevant searches into your MongoDB Atlas-backed applications, making it simpler for developers to focus on implementing other things.

## Prerequisites
In order to follow along with this tutorial, you will need a few things in place before you start:

 - An IDE or text editor that can support C# and Blazor for the most seamless development experience, such as Visual Studio, Visual Studio Code with the C# DevKit Extension installed, and JetBrains Rider.
 - An Atlas M0
   cluster,
   our free forever tier, perfect for development.
 - The sample dataset
   loaded into the
   cluster.
 - Your cluster connection
   string for use in your application settings later on.
 - A fork of the GitHub
   repo that we
   will be adding search to.

Once you have forked and then cloned the repo and have it locally, you will need to add your connection string into ```appsettings.Development.json``` and ```appsettings.json``` in the placeholder section in order to connect to your cluster when running the project.

> If you don’t want to follow along, the repo has a branch called “full-text-search” which has the final result implemented.

## Creating Atlas Search indexes
Before we can start adding Atlas Search to our application, we need to create search indexes inside Atlas. These indexes enable full-text search capabilities on our database. We want to specify what fields we wish to index.

Atlas Search does support dynamic indexes, which apply to all fields and adapt to any document shape changes. But for this tutorial, we are going to add a search index for a specific field, “title.”

 1. Inside Atlas, click “Browse Collections” to open the data explorer to view your newly loaded sample data.
 2. Select the “Atlas Search” tab at the top.
 3. Click the green “Create Search Index” button to load the index creation wizard.
 4. Select Visual Editor and then click “Next.”
 5. Give your index a name. What you choose is up to you.
 6. For “Database and Collection,” select “sample_mflix” to expand the database and select the “movies” collection. Then, click “Next.”
 7. In the final review section, click the “Refine Your Index” button below the “Index Configurations” table as we want to make some changes.
 8. Click “+ Add Field Mapping” about halfway down the page.
 9. In “Field Name,” search for “title.”
 10. For “Data Type,” select “Autocomplete.” This is because we want to have autocomplete available in our application so users can see results as they start typing.
 11. Click the “Add” button in the bottom right corner.
 12. Click “Save” and then “Create Search Index.”

After a few minutes, the search index will be set up and the application will be ready to be “searchified.”

If you prefer to use the JSON editor to simply copy and paste, you can use the following:
```json
{
  "mappings": {
    "dynamic": true,
    "fields": {
      "title": {
        "type": "autocomplete"
      }
    }
  }
}
```
## Implementing backend functionality
Now the database is set up to support Atlas Search with our new indexes, it's time to update the code in the application to support search. The code has an interface and service for talking to Atlas using the MongoDB C# driver which can be found in the ```Services``` folder.
### Adding a new method to IMongoDBService
First up is adding a new method for searching to the interface.

Open ```IMongoDBService.cs``` and add the following code:

```csharp
public IEnumerable MovieSearchByText (string textToSearch);
```

We return an IEnumerable of movie documents because multiple documents might match the search terms.

### Implementing the method in MongoDBService

Next up is adding the implementation to the service.

 1. Open ```MongoDBService.cs``` and paste in the following code:
```csharp
public IEnumerable MovieSearchByText(string textToSearch)
{             
// define fuzzy options
  SearchFuzzyOptions fuzzyOptions = new SearchFuzzyOptions()
  {
    MaxEdits = 1,
    PrefixLength = 1,   
    MaxExpansions = 256
  };
  
  // define and run pipeline
  var movies = _movies.Aggregate().Search(Builders.Search.Autocomplete(movie => movie.Title, 
  textToSearch, fuzzy: fuzzyOptions), indexName: "title").Project(Builders.Projection
  .Exclude(movie => movie.Id)).ToList();
  return movies;
}       
```
 Replace the value for ```indexName``` with the name you gave your search index.

Fuzzy search allows for approximate matching to a search term which can be helpful with things like typos or spelling mistakes. So we set up some fuzzy search options here, such as how close to the right term the characters need to be and how many characters at the start that must exactly match. 

Atlas Search is carried out using the $search aggregation stage, so we call ```.Aggregate()``` on the movies collection and then call the ``Search``` method.

We then pass a builder to the search stage to search against the title using our passed-in search text and the fuzzy options from earlier.

The ```.Project()``` stage is optional but we’re going to include it because we don’t use the _id field in our application. So for performance reasons, it is always good to exclude any fields you know you won’t need to be returned.

You will also need to make sure the following using statements are present at the top of the class for the code to run later:

```chsarp
using SeeSharpMovies.Models;
using MongoDB.Driver;
using MongoDB.Driver.Search;
```
Just like that, the back end is ready to accept a search term, search the collection for any matching documents, and return the result.
## Implementing frontend functionality
Now the back end is ready to accept our searches, it is time to implement it on the front end so users can search. This will be split into two parts: the code in the front end for talking to the back end, and the search bar in HTML for typing into.

### Adding code to handle search
This application uses razor pages which support having code in the front end. If you look inside ```Home.razor``` in the ```Components/Pages``` folder, you will see there is already some code there for requesting all movies and pagination.

 1. Inside the ```@code``` block, underneath the existing variables, add the following code:
```csharp
string searchTerm;
Timer debounceTimer;
int debounceInterval = 200;
```
As expected, there is a string variable to hold the search term, but the other two values might not seem obvious. In development, where you are accepting input and then calling some kind of service, you want to avoid calling it too often. So you can implement something called *debounce* which handles that. You will see that implemented later but it uses a timer and an interval — in this case, 200 milliseconds.

2. Add the following code after the existing methods:
```csharp
private void SearchMovies()
    {
        if (string.IsNullOrWhiteSpace(searchTerm))
        {
            movies = MongoDBService.GetAllMovies();
        }
        else
        {
            movies = MongoDBService.MovieSearchByText(searchTerm);
        }
   }

void DebounceSearch(object state)
    {
        if (string.IsNullOrWhiteSpace(searchTerm))
        {
            SearchMovies();
        }
        else
        {
            InvokeAsync(() =>
            {
                SearchMovies();
                StateHasChanged();
            });
        }
    }

void OnSearchInput(ChangeEventArgs e)
    {
            searchTerm = e.Value.ToString();
            debounceTimer?.Dispose();
            debounceTimer = new Timer(DebounceSearch, null, debounceInterval, Timeout.Infinite);
    }

```
SearchMovies: This method handles an empty search box as trying to search on nothing will cause it to error. So if there is nothing in the search box, it fetches all movies again. Otherwise, it calls the backend method we implemented previously to search by that term.

DebounceSearch: This calls search movies and if there is a search term available, it also tells the component that the stage has changed.

OnSearchInput: This will be called later by our search box but this is an event handler that says that when there is a change event, set the search term to the value of the box, reset the debounce timer, and start it again from the timer interval, passing in the ```DebounceSearch``` method as a callback function.

Now we have the code to smoothly handle receiving input and calling the back end, it is time to add the search box to our UI.

### Adding a search bar
Adding the search bar is really simple. We are going to add it to the header component already present on the home page.

After the link tag with the text “See Sharp Movies,” add the following HTML:

```html

    

```
## Testing the search functionality
Now we have the backend code available and the front end has the search box and a way to send the search term to the back end, it's time to run the application and see it in action.

Run the application, enter a search term in the box, and test the result. 

## Summary 
Excellent! You now have a Blazor application with search functionality added and a good starting point for using full-text search in your applications going forward.

If you want to learn more about Atlas Search, including more features than just autocomplete, you can take an amazing Atlas Search workshop created by my colleague or view the docs]https://www.mongodb.com/docs/manual/text-search/). If you have questions or feedback, join us in the [Community Forums.