π Add Full-text Search to Your Application
So far, you've seen how to use the search indexes in the aggregation pipeline builder or Compass. But what if you want to use the search index in your application?
To do so, you will need to add some code to your application.
- π NodeJS/Express
- βοΈ Java Spring Boot
To use the aggregation pipeline in Node.js, you will need to use the aggregate method on the collection object. This method takes an array of stages as an argument and returns a cursor. You can then use the cursor to iterate over the results or use the toArray method to get the results in an array.
const documents = await collection.aggregate(aggregationPipelines).toArray();
You now know everything you need to add full-text search capabilities to your application.
Adding search to the library appβ
Open up the code from the server file server/src/controllers/books.ts. In there, look for the searchBooks function.
Right now, it uses a regular expression to query the database.
public async searchBooks(query: string): Promise<Book[]> {
const books = await collections?.books?.find({ title: {$regex: new RegExp(query, "i")} }).toArray();
return books;
}
While this code works to a certain extent, it is less than optimal. As the dataset grows, the performance of this query will degrade because it will have to scan the entire collection. You cannot query the index with a regular expression. Furthermore, the query only matches on the title and only for the exact sequence of characters.
Change this code to use the search index instead. You will need to use the $search stage in the aggregation pipeline. Have your search cover the title, the author name, and the genres array.
This code will go in the server/src/controllers/books.ts file, in the searchBooks function.
Click here to see the answer
public async searchBooks(query: string): Promise<Book[]> {
const aggregationPipeline = [
{
$search: {
index: 'fulltextsearch',
text: {
query,
path: ['title', 'authors.name', 'genres']
}
}
}
];
const books = await collections?.books?.aggregate(aggregationPipeline).toArray() as Book[];
return books;
}
To use the aggregation pipeline in Java, you can build your search stage using the $search operator and then create an Aggregation. Finally, run the aggregation with MongoTemplate.aggregate, mapping the results directly to your domain class.
Adding search to the library appβ
Open the BookService class in your Java project and look for the searchBooks method.
Right now, it uses a repository method with a simple text search:
public List<Book> searchBooks(String theTerm) {
PageRequest request = PageRequest.of(0, 10, Sort.unsorted());
return bookRepository.searchByText(theTerm, request);
}
While this code works to some extent, it is not optimal. As the dataset grows, performance will degrade because the search is not using the dedicated Atlas Search index. It also limits the query to very basic text matching. Change this method to use the $search stage in the aggregation pipeline instead. Your search should cover:
- the
title - the
authors.name - the
genresarray
Use the aggregation code you saw earlier to build the $search stage and run it with MongoTemplate.aggregate.
Click here to see the answer
public List<Book> searchBooks(String theTerm) {
AggregationOperation searchStage = context -> new Document("$search",
new Document("index", "fulltextsearch")
.append("text", new Document("query", theTerm)
.append("path", Arrays.asList("title", "authors.name", "genres")))
);
Aggregation aggregation = Aggregation.newAggregation(searchStage);
return mongoTemplate.aggregate(aggregation, "books", Book.class).getMappedResults();
}