MiniSearch is the main entrypoint class, implementing a full-text search engine in memory.

Type Parameters

  • T = any

    The type of the documents being indexed.

    Basic example:

    const documents = [
    {
    id: 1,
    title: 'Moby Dick',
    text: 'Call me Ishmael. Some years ago...',
    category: 'fiction'
    },
    {
    id: 2,
    title: 'Zen and the Art of Motorcycle Maintenance',
    text: 'I can see by my watch...',
    category: 'fiction'
    },
    {
    id: 3,
    title: 'Neuromancer',
    text: 'The sky above the port was...',
    category: 'fiction'
    },
    {
    id: 4,
    title: 'Zen and the Art of Archery',
    text: 'At first sight it must seem...',
    category: 'non-fiction'
    },
    // ...and more
    ]

    // Create a search engine that indexes the 'title' and 'text' fields for
    // full-text search. Search results will include 'title' and 'category' (plus the
    // id field, that is always stored and returned)
    const miniSearch = new MiniSearch({
    fields: ['title', 'text'],
    storeFields: ['title', 'category']
    })

    // Add documents to the index
    miniSearch.addAll(documents)

    // Search for documents:
    let results = miniSearch.search('zen art motorcycle')
    // => [
    // { id: 2, title: 'Zen and the Art of Motorcycle Maintenance', category: 'fiction', score: 2.77258 },
    // { id: 4, title: 'Zen and the Art of Archery', category: 'non-fiction', score: 1.38629 }
    // ]

Constructors

  • Type Parameters

    • T = any

    Parameters

    • options: Options<T>

      Configuration options

      Examples:

      // Create a search engine that indexes the 'title' and 'text' fields of your
      // documents:
      const miniSearch = new MiniSearch({ fields: ['title', 'text'] })

      ID Field:

      // Your documents are assumed to include a unique 'id' field, but if you want
      // to use a different field for document identification, you can set the
      // 'idField' option:
      const miniSearch = new MiniSearch({ idField: 'key', fields: ['title', 'text'] })

      Options and defaults:

      // The full set of options (here with their default value) is:
      const miniSearch = new MiniSearch({
      // idField: field that uniquely identifies a document
      idField: 'id',

      // extractField: function used to get the value of a field in a document.
      // By default, it assumes the document is a flat object with field names as
      // property keys and field values as string property values, but custom logic
      // can be implemented by setting this option to a custom extractor function.
      extractField: (document, fieldName) => document[fieldName],

      // tokenize: function used to split fields into individual terms. By
      // default, it is also used to tokenize search queries, unless a specific
      // `tokenize` search option is supplied. When tokenizing an indexed field,
      // the field name is passed as the second argument.
      tokenize: (string, _fieldName) => string.split(SPACE_OR_PUNCTUATION),

      // processTerm: function used to process each tokenized term before
      // indexing. It can be used for stemming and normalization. Return a falsy
      // value in order to discard a term. By default, it is also used to process
      // search queries, unless a specific `processTerm` option is supplied as a
      // search option. When processing a term from a indexed field, the field
      // name is passed as the second argument.
      processTerm: (term, _fieldName) => term.toLowerCase(),

      // searchOptions: default search options, see the `search` method for
      // details
      searchOptions: undefined,

      // fields: document fields to be indexed. Mandatory, but not set by default
      fields: undefined

      // storeFields: document fields to be stored and returned as part of the
      // search results.
      storeFields: []
      })

    Returns MiniSearch<T>

Properties

wildcard: typeof wildcard = ...

The special wildcard symbol that can be passed to MiniSearch#search to match all documents

Accessors

  • get dirtCount(): number
  • The number of documents discarded since the most recent vacuuming

    Returns number

  • get dirtFactor(): number
  • A number between 0 and 1 giving an indication about the proportion of documents that are discarded, and can therefore be cleaned up by vacuuming. A value close to 0 means that the index is relatively clean, while a higher value means that the index is relatively dirty, and vacuuming could release memory.

    Returns number

  • get documentCount(): number
  • Total number of documents available to search

    Returns number

  • get isVacuuming(): boolean
  • Is true if a vacuuming operation is ongoing, false otherwise

    Returns boolean

  • get termCount(): number
  • Number of terms in the index

    Returns number

Methods

  • Adds a document to the index

    Parameters

    • document: T

      The document to be indexed

    Returns void

  • Adds all the given documents to the index

    Parameters

    • documents: readonly T[]

      An array of documents to be indexed

    Returns void

  • Adds all the given documents to the index asynchronously.

    Returns a promise that resolves (to undefined) when the indexing is done. This method is useful when index many documents, to avoid blocking the main thread. The indexing is performed asynchronously and in chunks.

    Parameters

    • documents: readonly T[]

      An array of documents to be indexed

    • options: {
          chunkSize?: number;
      } = {}

      Configuration options

      • Optional chunkSize?: number

    Returns Promise<void>

    A promise resolving to undefined when the indexing is done

  • Provide suggestions for the given search query

    The result is a list of suggested modified search queries, derived from the given search query, each with a relevance score, sorted by descending score.

    By default, it uses the same options used for search, except that by default it performs prefix search on the last term of the query, and combine terms with 'AND' (requiring all query terms to match). Custom options can be passed as a second argument. Defaults can be changed upon calling the MiniSearch constructor, by passing a autoSuggestOptions option.

    Basic usage:

    // Get suggestions for 'neuro':
    miniSearch.autoSuggest('neuro')
    // => [ { suggestion: 'neuromancer', terms: [ 'neuromancer' ], score: 0.46240 } ]

    Multiple words:

    // Get suggestions for 'zen ar':
    miniSearch.autoSuggest('zen ar')
    // => [
    // { suggestion: 'zen archery art', terms: [ 'zen', 'archery', 'art' ], score: 1.73332 },
    // { suggestion: 'zen art', terms: [ 'zen', 'art' ], score: 1.21313 }
    // ]

    Fuzzy suggestions:

    // Correct spelling mistakes using fuzzy search:
    miniSearch.autoSuggest('neromancer', { fuzzy: 0.2 })
    // => [ { suggestion: 'neuromancer', terms: [ 'neuromancer' ], score: 1.03998 } ]

    Filtering:

    // Get suggestions for 'zen ar', but only within the 'fiction' category
    // (assuming that 'category' is a stored field):
    miniSearch.autoSuggest('zen ar', {
    filter: (result) => result.category === 'fiction'
    })
    // => [
    // { suggestion: 'zen archery art', terms: [ 'zen', 'archery', 'art' ], score: 1.73332 },
    // { suggestion: 'zen art', terms: [ 'zen', 'art' ], score: 1.21313 }
    // ]

    Parameters

    • queryString: string

      Query string to be expanded into suggestions

    • options: SearchOptions = {}

      Search options. The supported options and default values are the same as for the MiniSearch#search method, except that by default prefix search is performed on the last term in the query, and terms are combined with 'AND'.

    Returns Suggestion[]

    A sorted array of suggestions sorted by relevance score.

  • Discards the document with the given ID, so it won't appear in search results

    It has the same visible effect of MiniSearch.remove (both cause the document to stop appearing in searches), but a different effect on the internal data structures:

    • MiniSearch#remove requires passing the full document to be removed as argument, and removes it from the inverted index immediately.

    • MiniSearch#discard instead only needs the document ID, and works by marking the current version of the document as discarded, so it is immediately ignored by searches. This is faster and more convenient than MiniSearch#remove, but the index is not immediately modified. To take care of that, vacuuming is performed after a certain number of documents are discarded, cleaning up the index and allowing memory to be released.

    After discarding a document, it is possible to re-add a new version, and only the new version will appear in searches. In other words, discarding and re-adding a document works exactly like removing and re-adding it. The MiniSearch.replace method can also be used to replace a document with a new version.

    Details about vacuuming

    Repetite calls to this method would leave obsolete document references in the index, invisible to searches. Two mechanisms take care of cleaning up: clean up during search, and vacuuming.

    • Upon search, whenever a discarded ID is found (and ignored for the results), references to the discarded document are removed from the inverted index entries for the search terms. This ensures that subsequent searches for the same terms do not need to skip these obsolete references again.

    • In addition, vacuuming is performed automatically by default (see the autoVacuum field in Options) after a certain number of documents are discarded. Vacuuming traverses all terms in the index, cleaning up all references to discarded documents. Vacuuming can also be triggered manually by calling MiniSearch#vacuum.

    Parameters

    • id: any

      The ID of the document to be discarded

    Returns void

  • Discards the documents with the given IDs, so they won't appear in search results

    It is equivalent to calling MiniSearch#discard for all the given IDs, but with the optimization of triggering at most one automatic vacuuming at the end.

    Note: to remove all documents from the index, it is faster and more convenient to call MiniSearch.removeAll with no argument, instead of passing all IDs to this method.

    Parameters

    • ids: readonly any[]

    Returns void

  • Returns the stored fields (as configured in the storeFields constructor option) for the given document ID. Returns undefined if the document is not present in the index.

    Parameters

    • id: any

      The document ID

    Returns undefined | Record<string, unknown>

  • Returns true if a document with the given ID is present in the index and available for search, false otherwise

    Parameters

    • id: any

      The document ID

    Returns boolean

  • Removes the given document from the index.

    The document to remove must NOT have changed between indexing and removal, otherwise the index will be corrupted.

    This method requires passing the full document to be removed (not just the ID), and immediately removes the document from the inverted index, allowing memory to be released. A convenient alternative is MiniSearch#discard, which needs only the document ID, and has the same visible effect, but delays cleaning up the index until the next vacuuming.

    Parameters

    • document: T

      The document to be removed

    Returns void

  • Removes all the given documents from the index. If called with no arguments, it removes all documents from the index.

    Parameters

    • Optional documents: readonly T[]

      The documents to be removed. If this argument is omitted, all documents are removed. Note that, for removing all documents, it is more efficient to call this method with no arguments than to pass all documents.

    Returns void

  • It replaces an existing document with the given updated version

    It works by discarding the current version and adding the updated one, so it is functionally equivalent to calling MiniSearch#discard followed by MiniSearch#add. The ID of the updated document should be the same as the original one.

    Since it uses MiniSearch#discard internally, this method relies on vacuuming to clean up obsolete document references from the index, allowing memory to be released (see MiniSearch#discard).

    Parameters

    • updatedDocument: T

      The updated document to replace the old version with

    Returns void

  • Search for documents matching the given search query.

    The result is a list of scored document IDs matching the query, sorted by descending score, and each including data about which terms were matched and in which fields.

    Basic usage:

    // Search for "zen art motorcycle" with default options: terms have to match
    // exactly, and individual terms are joined with OR
    miniSearch.search('zen art motorcycle')
    // => [ { id: 2, score: 2.77258, match: { ... } }, { id: 4, score: 1.38629, match: { ... } } ]

    Restrict search to specific fields:

    // Search only in the 'title' field
    miniSearch.search('zen', { fields: ['title'] })

    Field boosting:

    // Boost a field
    miniSearch.search('zen', { boost: { title: 2 } })

    Prefix search:

    // Search for "moto" with prefix search (it will match documents
    // containing terms that start with "moto" or "neuro")
    miniSearch.search('moto neuro', { prefix: true })

    Fuzzy search:

    // Search for "ismael" with fuzzy search (it will match documents containing
    // terms similar to "ismael", with a maximum edit distance of 0.2 term.length
    // (rounded to nearest integer)
    miniSearch.search('ismael', { fuzzy: 0.2 })

    Combining strategies:

    // Mix of exact match, prefix search, and fuzzy search
    miniSearch.search('ismael mob', {
    prefix: true,
    fuzzy: 0.2
    })

    Advanced prefix and fuzzy search:

    // Perform fuzzy and prefix search depending on the search term. Here
    // performing prefix and fuzzy search only on terms longer than 3 characters
    miniSearch.search('ismael mob', {
    prefix: term => term.length > 3
    fuzzy: term => term.length > 3 ? 0.2 : null
    })

    Combine with AND:

    // Combine search terms with AND (to match only documents that contain both
    // "motorcycle" and "art")
    miniSearch.search('motorcycle art', { combineWith: 'AND' })

    Combine with AND_NOT:

    There is also an AND_NOT combinator, that finds documents that match the first term, but do not match any of the other terms. This combinator is rarely useful with simple queries, and is meant to be used with advanced query combinations (see later for more details).

    Filtering results:

    // Filter only results in the 'fiction' category (assuming that 'category'
    // is a stored field)
    miniSearch.search('motorcycle art', {
    filter: (result) => result.category === 'fiction'
    })

    Wildcard query

    Searching for an empty string (assuming the default tokenizer) returns no results. Sometimes though, one needs to match all documents, like in a "wildcard" search. This is possible by passing the special value MiniSearch.wildcard as the query:

    // Return search results for all documents
    miniSearch.search(MiniSearch.wildcard)

    Note that search options such as filter and boostDocument are still applied, influencing which results are returned, and their order:

    // Return search results for all documents in the 'fiction' category
    miniSearch.search(MiniSearch.wildcard, {
    filter: (result) => result.category === 'fiction'
    })

    Advanced combination of queries:

    It is possible to combine different subqueries with OR, AND, and AND_NOT, and even with different search options, by passing a query expression tree object as the first argument, instead of a string.

    // Search for documents that contain "zen" and ("motorcycle" or "archery")
    miniSearch.search({
    combineWith: 'AND',
    queries: [
    'zen',
    {
    combineWith: 'OR',
    queries: ['motorcycle', 'archery']
    }
    ]
    })

    // Search for documents that contain ("apple" or "pear") but not "juice" and
    // not "tree"
    miniSearch.search({
    combineWith: 'AND_NOT',
    queries: [
    {
    combineWith: 'OR',
    queries: ['apple', 'pear']
    },
    'juice',
    'tree'
    ]
    })

    Each node in the expression tree can be either a string, or an object that supports all SearchOptions fields, plus a queries array field for subqueries.

    Note that, while this can become complicated to do by hand for complex or deeply nested queries, it provides a formalized expression tree API for external libraries that implement a parser for custom query languages.

    Parameters

    • query: Query

      Search query

    • searchOptions: SearchOptions = {}

      Search options. Each option, if not given, defaults to the corresponding value of searchOptions given to the constructor, or to the library default.

    Returns SearchResult[]

  • Allows serialization of the index to JSON, to possibly store it and later deserialize it with MiniSearch.loadJSON.

    Normally one does not directly call this method, but rather call the standard JavaScript JSON.stringify() passing the MiniSearch instance, and JavaScript will internally call this method. Upon deserialization, one must pass to MiniSearch.loadJSON the same options used to create the original instance that was serialized.

    Usage:

    // Serialize the index:
    let miniSearch = new MiniSearch({ fields: ['title', 'text'] })
    miniSearch.addAll(documents)
    const json = JSON.stringify(miniSearch)

    // Later, to deserialize it:
    miniSearch = MiniSearch.loadJSON(json, { fields: ['title', 'text'] })

    Returns AsPlainObject

    A plain-object serializable representation of the search index.

  • Triggers a manual vacuuming, cleaning up references to discarded documents from the inverted index

    Vacuuming is only useful for applications that use the MiniSearch#discard or MiniSearch#replace methods.

    By default, vacuuming is performed automatically when needed (controlled by the autoVacuum field in Options), so there is usually no need to call this method, unless one wants to make sure to perform vacuuming at a specific moment.

    Vacuuming traverses all terms in the inverted index in batches, and cleans up references to discarded documents from the posting list, allowing memory to be released.

    The method takes an optional object as argument with the following keys:

    • batchSize: the size of each batch (1000 by default)

    • batchWait: the number of milliseconds to wait between batches (10 by default)

    On large indexes, vacuuming could have a non-negligible cost: batching avoids blocking the thread for long, diluting this cost so that it is not negatively affecting the application. Nonetheless, this method should only be called when necessary, and relying on automatic vacuuming is usually better.

    It returns a promise that resolves (to undefined) when the clean up is completed. If vacuuming is already ongoing at the time this method is called, a new one is enqueued immediately after the ongoing one, and a corresponding promise is returned. However, no more than one vacuuming is enqueued on top of the ongoing one, even if this method is called more times (enqueuing multiple ones would be useless).

    Parameters

    Returns Promise<void>

  • Returns the default value of an option. It will throw an error if no option with the given name exists.

    Parameters

    • optionName: string

      Name of the option

    Returns any

    The default value of the given option

    Usage:

    // Get default tokenizer
    MiniSearch.getDefault('tokenize')

    // Get default term processor
    MiniSearch.getDefault('processTerm')

    // Unknown options will throw an error
    MiniSearch.getDefault('notExisting')
    // => throws 'MiniSearch: unknown option "notExisting"'
  • Deserializes a JSON index (serialized with JSON.stringify(miniSearch)) and instantiates a MiniSearch instance. It should be given the same options originally used when serializing the index.

    Usage:

    // If the index was serialized with:
    let miniSearch = new MiniSearch({ fields: ['title', 'text'] })
    miniSearch.addAll(documents)

    const json = JSON.stringify(miniSearch)
    // It can later be deserialized like this:
    miniSearch = MiniSearch.loadJSON(json, { fields: ['title', 'text'] })

    Type Parameters

    • T = any

    Parameters

    • json: string

      JSON-serialized index

    • options: Options<T>

      configuration options, same as the constructor

    Returns MiniSearch<T>

    An instance of MiniSearch deserialized from the given JSON.

  • Async equivalent of MiniSearch.loadJSON

    This function is an alternative to MiniSearch.loadJSON that returns a promise, and loads the index in batches, leaving pauses between them to avoid blocking the main thread. It tends to be slower than the synchronous version, but does not block the main thread, so it can be a better choice when deserializing very large indexes.

    Type Parameters

    • T = any

    Parameters

    • json: string

      JSON-serialized index

    • options: Options<T>

      configuration options, same as the constructor

    Returns Promise<MiniSearch<T>>

    A Promise that will resolve to an instance of MiniSearch deserialized from the given JSON.