Firestore Full Text Search with Meili

Torkel Velure
Firebase Developers
4 min readAug 25, 2021

Fjelltoppjakten now has over 16 000 users, and a highly requested feature has been to search for users by name.

We have a users collection in Firestore with the following data structure:

users/$userId {
name: String
imgUrl: String,
location: String
}

We wanted to implement a search field in the app so that users can find their friends, and they should be able to search for partial names and have some leeway in typing mistakes.

Firebase does not have a good solution for that, the closest thing might be a greater than or equal to query, but that does not account for typos and you can’t search for last names.

The Firebase docs recommend using a 3rd-party solution and there are several alternatives. A popular one is to use the Search with Algolia extension. However, Algolia can get expensive, especially if you want to implement auto-complete search. It costs around $1 per 1000 search requests.

Enter MeiliSearch

If you have a couple hours to spare and want to save some money, a nice alternative is MeiliSearch, an open source search engine you can host yourself. It is easy to use, fast and typo-tolerant. It has a REST API which makes it easy to implement in our Android and iOS apps. We spent in total 2 hours from discovering Meili to having a working auto-complete search feature in production.

Search as you type
Designed to answer in less than 50 ms. It allows users to respond to the search in real-time, narrowing their search terms or stopping early if they’ve found what they’re looking for.

Typo Tolerant
MeiliSearch offers a typo-tolerant and natural query language search experience.

Synonyms
In MeiliSearch, words can be associated. Search should not be limited by some specific words.

https://www.meilisearch.com/

Deploy MeiliSearch

There are several guides on how to deploy Meili, but we found the easiest option to be the 1-click installer on Digital Ocean. It costs ~$6 every month for the cheapest instance. You can also get $100 free credits if you use a referral link.

In the MeiliSearch docs, you can find guides on how to deploy it on other cloud providers, for example Google Cloud.

After deployment you should have an API-key and a url to your API.

Add documents to Meili

To search for our users in Meili, we need to add documents to the Meili database with anid attribute(required) and whatever other attributes you want to search for, in this casename , and additionally imgUrl(users profile image) and location to make the search result prettier.

To add a document you simply send a post request to /indexes/:index_uid/documents with a JSON array of documents in the body, and aX-Meili-API-Key header.

We added all our users to Meili with a Firebase Cloud Function:

Just deploy the function and trigger it by visiting https://us-central1-<project-id>.cloudfunctions.net/importToMeili

Updating documents

Every time a document is added, deleted or a user changes their name, we also want to add/replace the document in Meili. We can easily do that with Firebase Cloud Functions.

MeiliSearch uses a document database, just like Firestore, so you can add whatever fields you want. You could simply add more attributes to the addOrReplaceMeiliUser function if necessary.

We added the users name, location and profile image, so we can use them in the search result screen. That means we don’t have to fetch anything from Firestore, saving tons of reads! We only have to fetch from Firestore if the user actually clicks on a profile to view more information.

Searching for documents

Now that we have all documents in MeiliSearch, we can start searching for users.

MeiliSearch has official libraries/SDK’s for many languages and frameworks, like Java, Swift, JavaScript, Vue, React, Angular.. However, as we were just doing simple search queries, we chose to use the REST API directly.

Filtering

By default MeiliSearch will search in all the attributes of the documents. We can fix that by either using a filter query, or updating the index. We chose to update the index so that the search only works on the name attribute:

curl \
-X POST 'MEILi_API_URL/indexes/users/settings' \
--data '{
"searchableAttributes": [
"name"
]
}'

Searching

You can search with either a GET or POST request to /indexes/users/search, however the docs recommend using a POST request, as it allows for preflight requests to be cached.

Here we search for “tomas”, with a limit of 4:

curl \
-X POST 'MEILI_API_URL/indexes/users/search' \
--data '{ "q": "tomas", limit: 4 }'

We get back the query result in JSON format:

In the search results we don’t just find “Tomas”, but also “Thomas” and “Toma”, with the more relevant “Tomas” as the first result. This is the magic of MeiliSearch being typo tolerant!

Conclusion

In just a few hours we managed to implement full-text search in our app. It’s lightning fast, typo tolerant and even cheap to maintain. Our only requirement was to search for users names, which was a breeze to implement.

MeiliSearch has more complex features as well, but I haven’t tried any of them, as it wasn’t necessary for our search feature. You could implement pagination with offset and limit, create a list of synonyms, highlight relevant attributes with attributesToHighlight, only fetch certain attributes with attributesToRetrieve, ignore certain words with stopWords, and more.

--

--