Share the article
In this guide, we’ll delve into the concept of faceting in Meilisearch and how to use it to display facet names while filtering by IDs.
What is faceting?
Faceting is a technique used in search engines to classify search results into multiple categories or “facets”. These facets can be anything from categories, tags, price ranges, to even colors. This makes it easier for the user to navigate and filter through the results, providing a more refined and efficient search experience.
Why use the ID as a facet filter?
For most applications and users, filtering by facet names, such as the genre of movies, is often sufficient and intuitive. Facet names are human-readable and provide a clear idea of what the filter does. However, in some use cases, it is preferable to filter by ID for a couple of key reasons:
- Less prone to errors: IDs are usually simpler and standardized, making them less susceptible to typos or inconsistencies that might be present in facet names.
- Unique identifiers: In some databases, facet names might be repeated with slightly different characteristics, whereas IDs are always unique. This is especially useful in cases where you have items with similar or identical names but different properties.
By using IDs for filtering but displaying the corresponding facet names to the users, you can achieve the best of both worlds: efficiency and usability. This way, you are leveraging the strengths of both IDs and names, making your application robust and user-friendly.
The ID-to-name challenge
In Meilisearch, facets are a specialized use-case of filters. Essentially, you can use any attribute added to the filterableAttributes list as a facet. When you add a facet parameter to your search query, Meilisearch will return a facetDistribution object. This object provides the number of matching documents distributed among the values of the given facet.
However, if the field you’ve added to the filterableAttributes list is an ID, the facetDistribution object will return these IDs.
While IDs are great for back-end operations, they are not necessarily user-friendly or meaningful on the front-end. This is why you might want to map these IDs back to their corresponding facet names when displaying them in your user interface.
ID-to-name mapping in the frontend
Suppose you have a dataset of movies following the structure below:
You want a faceted search based on the movie genres, so you add genres.id to the filterable attributes list. In the UI, though, you want to display genres.name, so the user sees “Crime” instead of “7”.
Let’s dive into how you can accomplish this with InstantSearch and instant-meilisearch.
Using InstantSearch and instant-meilisearch
InstantSearch is an open-source front-end library to build search UIs. Instant-meilisearch is the go-to search client for integrating InstantSearch with Meilisearch.
To use instant-meilisearch with InstantSearch, you need to:
1. Import the required modules, including instantMeiliSearch
2. Create the search client with your Meilisearch host and search API key
instantMeiliSearch returns an object, so destructure searchClient from it. Assigning the whole return value to searchClient is a common mistake and leaves InstantSearch with no usable client.
3. Set up InstantSearch with your Meilisearch index name and the search client
In this guide, we’ll use InstantSearch’s refinementList widget to map IDs to user-friendly names.
This widget comes with an optional parameter called transformItems. This function receives the items (or facets) and allows you to transform them before they are displayed on the UI. It also includes the full results data in its parameters.
Each item, or facet, includes the following properties:
count: the number of occurrences of the facet in the result setvalue: the value used for refining (in our case it would be genres.id)label: the label to displayhighlighted: the highlighted label. This value is displayed in the default template
As you can see, highlighted is the label used by default in the refinementList widget.
With this information, we can use the transformItems function to display the genres.name instead of genres.id.
With this configuration, you’ll efficiently map IDs to more user-friendly names, enhancing the search experience for your users.
The full code should look like this:
This example shows how to implement ID-to-name mapping with vanilla JavaScript, but you can achieve similar results with your preferred frontend framework. Check out the respective documentation for React and Vue.
The Meilisearch instance in these examples is a Meilisearch Cloud project, which is the quickest way to get a host and search key to point InstantSearch at. The code is identical against a self-hosted instance.
For more things Meilisearch, you can subscribe to our newsletter. You can learn more about our product by checking out the roadmap and participating in our product discussions.
For anything else, join our developers community on Discord.
Frequently asked questions (FAQs)
What is faceting in Meilisearch?
Faceting groups search results into categories such as genre, brand, or price range, and reports how many results fall into each. In Meilisearch, facets are a specialized use of filters: any attribute in the index's filterableAttributes list can be used as a facet.
Can I filter by ID but display the name?
Yes. Add the ID field to filterableAttributes so refinement happens on the stable identifier, then map IDs back to names in the interface. With InstantSearch, the refinementList widget's transformItems option does the mapping just before the facet list renders.
Why filter by ID instead of by name?
IDs are unique and stable. Names can be duplicated across records with different properties, and they change, which silently breaks saved filters and links. Filtering by ID keeps refinement correct while the label shown to users stays human-readable.
Why does my instant-meilisearch client not work?
The most common cause is assigning the return value of instantMeiliSearch directly. It returns an object, so you need const { searchClient } = instantMeiliSearch(host, apiKey). Also check that you are using react-instantsearch rather than the deprecated react-instantsearch-dom or react-instantsearch-hooks-web packages.






