We recommend installing meilisearch-js
in your project with your package manager of choice.
npm install meilisearch
meilisearch-js
officially supports node
versions >= 14 and <= 18.
Instead of using a package manager, you may also import the library directly into your HTML via a CDN.
To use one of our SDKs, you must first have a running Meilisearch instance. Consult our documentation for instructions on how to download and launch Meilisearch.
After installing meilisearch-js
, you must import it into your application. There are many ways of doing that depending on your development environment.
import
syntaxUsage in an ES module environment:
import { MeiliSearch } from 'meilisearch'
const client = new MeiliSearch({
host: 'url',
apiKey: 'masterKey',
})
<script>
tagUsage in an HTML (or alike) file:
<script src='https://cdn.jsdelivr.net/npm/meilisearch@latest/dist/bundles/meilisearch.umd.js'></script>
<script>
const client = new MeiliSearch({
host: 'url',
apiKey: 'masterKey',
})
</script>
require
syntaxUsage in a back-end node.js or another environment supporting CommonJS modules:
const { MeiliSearch } = require('meilisearch')
const client = new MeiliSearch({
host: 'url',
apiKey: 'masterKey',
})
To use meilisearch-js
with React Native, you must also install react-native-url-polyfill.
Usage in a Deno environment:
import { MeiliSearch } from "https://esm.sh/meilisearch"
const client = new MeiliSearch({
host: 'url',
apiKey: 'masterKey',
})
Add documents
const { MeiliSearch } = require('meilisearch')
// Or if you are in a ES environment
import { MeiliSearch } from 'meilisearch'
;(async () => {
const client = new MeiliSearch({
host: 'url',
apiKey: 'masterKey',})
// An index is where the documents are stored.
const index = client.index('movies')
const documents = [
{ id: 1, title: 'Carol', genres: ['Romance', 'Drama'] },
{ id: 2, title: 'Wonder Woman', genres: ['Action', 'Adventure'] },
{ id: 3, title: 'Life of Pi', genres: ['Adventure', 'Drama'] },
{ id: 4, title: 'Mad Max: Fury Road', genres: ['Adventure', 'Science Fiction'] },
{ id: 5, title: 'Moana', genres: ['Fantasy', 'Action']},
{ id: 6, title: 'Philadelphia', genres: ['Drama'] },]
// If the index 'movies' does not exist, Meilisearch creates it when you first add the documents.
let response = await index.addDocuments(documents)
console.log(response) // => { "uid": 0 }
})()
Tasks such as document addition always return a unique identifier. You can use this identifier taskUid
to check the status (enqueued
, processing
, succeeded
or failed
) of a task.
// Meilisearch is typo-tolerant:
const search = await index.search('philoudelphia')
console.log(search)
Output:
{
"hits": [
{
"id": "6",
"title": "Philadelphia",
"genres": ["Drama"]
}
],
"offset": 0,
"limit": 20,
"estimatedTotalHits": 1,
"processingTimeMs": 1,
"query": "philoudelphia"
}
meilisearch-js supports all search parameters described in our main documentation website.
await index.search('wonder',{
attributesToHighlight: ['*']})
{"hits": [
{
"id": 2,
"title": "Wonder Woman",
"genres": ["Action", "Adventure"],
"_formatted": {
"id": "2",
"title": "<em>Wonder</em> Woman",
"genres": ["Action", "Adventure"]
}
}],"offset": 0,"limit": 20,"estimatedTotalHits": 1,"processingTimeMs": 0,"query": "wonder"}
To enable filtering, you must first add your attributes to the filterableAttributes index setting.
await index.updateAttributesForFaceting([
'id',
'genres'])
You only need to perform this operation once per index.
Note that Meilisearch rebuilds your index whenever you update filterableAttributes. Depending on the size of your dataset, this might take considerable time. You can track the process using the tasks API).
After you configured filterableAttributes, you can use the filter
search parameter to refine your search:
await index.search('wonder',{
filter: ['id > 1 AND genres = Action']})
{"hits": [
{
"id": 2,
"title": "Wonder Woman",
"genres": ["Action","Adventure"]
}],"offset": 0,"limit": 20,"estimatedTotalHits": 1,"processingTimeMs": 0,"query": "wonder"}
Placeholder search makes it possible to receive hits based on your parameters without having any query (q). For example, in a movies database you can run an empty query to receive all results filtered by genre.
await index.search('',{
filter: ['genres = fantasy'],
facets: ['genres']})
{"hits": [
{
"id": 2,
"title": "Wonder Woman",
"genres": ["Action","Adventure"]
},
{
"id": 5,
"title": "Moana",
"genres": ["Fantasy","Action"]
}],"offset": 0,"limit": 20,"estimatedTotalHits": 2,"processingTimeMs": 0,"query": "","facetDistribution": {
"genres": {
"Action": 2,
"Fantasy": 1,
"Adventure": 1
}}}
Note that to enable faceted search on your dataset you need to add genres to the filterableAttributes index setting. For more information on filtering and faceting, consult our documentation settings.
You can abort a pending search request by providing an AbortSignal to the request.
const controller = new AbortController()
index
.search('wonder', {}, {
signal: controller.signal,}).then((response) => {
/** ... */}).catch((e) => {
/** Catch AbortError here. */})
controller.abort()
client.index<T>('xxx').search(query: string, options: SearchParams = {}, config?: Partial<Request>): Promise<SearchResponse<T>>
client.index<T>('xxx').searchGet(query: string, options: SearchParams = {}, config?: Partial<Request>): Promise<SearchResponse<T>>
client.multiSearch(queries?: MultiSearchParams, config?: Partial<Request>): Promise<Promise<MultiSearchResponse<T>>>
multiSearch uses the POST method when performing its request to Meilisearch.
client.index<T>('myIndex').searchForFacetValues(params: SearchForFacetValuesParams, config?: Partial<Request>): Promise<SearchForFacetValuesResponse>
client.index('myIndex').addDocuments(documents: Document<T>[]): Promise<EnqueuedTask>
client.index('myIndex').addDocumentsFromString(documents: string, contentType: ContentType, queryParams: RawDocumentAdditionOptions): Promise<EnqueuedTask>
client.index('myIndex').addDocumentsInBatches(documents: Document<T>[], batchSize = 1000): Promise<EnqueuedTask[]>
client.index('myIndex').updateDocuments(documents: Array<Document<Partial<T>>>): Promise<EnqueuedTask>
client.index('myIndex').updateDocumentsFromString(documents: string, contentType: ContentType, queryParams: RawDocumentAdditionOptions): Promise<EnqueuedTask>
client.index('myIndex').updateDocumentsInBatches(documents: Array<Document<Partial<T>>>, batchSize = 1000): Promise<EnqueuedTask[]>
client.index.getDocuments(parameters: DocumentsQuery = {}): Promise<DocumentsResults<T>>>
client.index('myIndex').getDocument(documentId: string): Promise<Document<T>>
client.index('myIndex').deleteDocument(documentId: string | number): Promise<EnqueuedTask>
client.index('myIndex').deleteDocuments(params: DocumentsDeletionQuery | DocumentsIds): Promise<EnqueuedTask>
client.index('myIndex').deleteAllDocuments(): Promise<Types.EnqueuedTask>
client.getTasks(parameters: TasksQuery): Promise<TasksResults>
client.getTask(uid: number): Promise<Task>
client.deleteTasks(parameters: DeleteTasksQuery = {}): Promise<EnqueuedTask>
client.cancelTasks(parameters: CancelTasksQuery = {}): Promise<EnqueuedTask>
client.index('myIndex').getTasks(parameters: TasksQuery): Promise<TasksResults>
client.index('myIndex').getTask(uid: number): Promise<Task>
client.waitForTask(uid: number, { timeOutMs?: number, intervalMs?: number }): Promise<Task>
client.index('myIndex').waitForTask(uid: number, { timeOutMs?: number, intervalMs?: number }): Promise<Task>
client.waitForTasks(uids: number[], { timeOutMs?: number, intervalMs?: number }): Promise<Task[]>
client.index('myIndex').waitForTasks(uids: number[], { timeOutMs?: number, intervalMs?: number }): Promise<Task[]>
client.getIndexes(parameters: IndexesQuery): Promise<IndexesResults<Index[]>>
client.getRawIndexes(parameters: IndexesQuery): Promise<IndexesResults<IndexObject[]>>
client.createIndex<T>(uid: string, options?: IndexOptions): Promise<EnqueuedTask>
client.index<T>(uid: string): Index<T>
client.getIndex<T>(uid: string): Promise<Index<T>>
client.getRawIndex(uid: string): Promise<IndexObject>
client.index('myIndex').getRawInfo(): Promise<IndexObject>
client.updateIndex(uid: string, options: IndexOptions): Promise<EnqueuedTask>
client.index('myIndex').update(data: IndexOptions): Promise<EnqueuedTask>
client.deleteIndex(uid): Promise<void>
client.index('myIndex').delete(): Promise<void>
client.index('myIndex').getStats(): Promise<IndexStats>
client.index('myIndex').fetchInfo(): Promise<Index>
client.index('myIndex').fetchPrimaryKey(): Promise<string | undefined>
client.swapIndexes(params: SwapIndexesParams): Promise<EnqueuedTask>
client.index('myIndex').getSettings(): Promise<Settings>
client.index('myIndex').updateSettings(settings: Settings): Promise<EnqueuedTask>
client.index('myIndex').resetSettings(): Promise<EnqueuedTask>
client.index('myIndex').getPagination(): Promise<PaginationSettings>
client.index('myIndex').updatePagination(pagination: PaginationSettings): Promise<EnqueuedTask>
client.index('myIndex').resetPagination(): Promise<EnqueuedTask>
client.index('myIndex').getSynonyms(): Promise<Synonyms>
client.index('myIndex').updateSynonyms(synonyms: Synonyms): Promise<EnqueuedTask>
client.index('myIndex').resetSynonyms(): Promise<EnqueuedTask>
client.index('myIndex').getStopWords(): Promise<string[]>
client.index('myIndex').updateStopWords(stopWords: string[] | null ): Promise<EnqueuedTask>
client.index('myIndex').resetStopWords(): Promise<EnqueuedTask>
client.index('myIndex').getRankingRules(): Promise<string[]>
client.index('myIndex').updateRankingRules(rankingRules: string[] | null): Promise<EnqueuedTask>
client.index('myIndex').resetRankingRules(): Promise<EnqueuedTask>
client.index('myIndex').getDistinctAttribute(): Promise<string | void>
client.index('myIndex').updateDistinctAttribute(distinctAttribute: string | null): Promise<EnqueuedTask>
client.index('myIndex').resetDistinctAttribute(): Promise<EnqueuedTask>
client.index('myIndex').getSearchableAttributes(): Promise<string[]>
client.index('myIndex').updateSearchableAttributes(searchableAttributes: string[] | null): Promise<EnqueuedTask>
client.index('myIndex').resetSearchableAttributes(): Promise<EnqueuedTask>
client.index('myIndex').getDisplayedAttributes(): Promise<string[]>
client.index('myIndex').updateDisplayedAttributes(displayedAttributes: string[] | null): Promise<EnqueuedTask>
client.index('myIndex').resetDisplayedAttributes(): Promise<EnqueuedTask>
client.index('myIndex').getFilterableAttributes(): Promise<string[]>
client.index('myIndex').updateFilterableAttributes(filterableAttributes: string[] | null): Promise<EnqueuedTask>
client.index('myIndex').resetFilterableAttributes(): Promise<EnqueuedTask>
client.index('myIndex').getSortableAttributes(): Promise<string[]>
client.index('myIndex').updateSortableAttributes(sortableAttributes: string[] | null): Promise<EnqueuedTask>
client.index('myIndex').resetSortableAttributes(): Promise<EnqueuedTask>
client.index('myIndex').getFaceting(): Promise<Faceting>
client.index('myIndex').updateFaceting(faceting: Faceting): Promise<EnqueuedTask>
client.index('myIndex').resetFaceting(): Promise<EnqueuedTask>
client.index('myIndex').getTypoTolerance(): Promise<TypoTolerance>
client.index('myIndex').updateTypoTolerance(typoTolerance: TypoTolerance | null): Promise<EnqueuedTask>
client.index('myIndex').resetTypoTolerance(): Promise<EnqueuedTask>
client.getKeys(parameters: KeysQuery): Promise<KeysResults>
client.getKey(keyOrUid: string): Promise<Key>
client.createKey(options: KeyCreation): Promise<Key>
client.updateKey(keyOrUid: string, options: KeyUpdate): Promise<Key>
client.deleteKey(keyOrUid: string): Promise<void>
client.isHealthy(): Promise<boolean>
client.health(): Promise<Health>
client.getStats(): Promise<Stats>
client.getVersion(): Promise<Version>
client.createDump(): Promise<EnqueuedTask>