Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ const searchClient = instantMeiliSearch(
- [`finitePagination`](#finite-pagination): Used to work with the [`pagination`](#-pagination) widget (default: `false`) .
- [`primaryKey`](#primary-key): Specify the primary key of your documents (default `undefined`).
- [`keepZeroFacets`](#keep-zero-facets): Show the facets value even when they have 0 matches (default `false`).
- [`matchingStrategy`](#matching-strategy): Determine the search strategy on words matching (default `last`).

The options are added as the third parameter of the `instantMeilisearch` function.

Expand Down Expand Up @@ -170,6 +171,21 @@ genres:
{ keepZeroFacets : true } // default: false
```

### Matching strategy

`matchingStrategy` gives you the possibility to chose how Meilisearch should handle the presence of multiple query words.

For example, if your query is `Hello world` by default Meilisearch returns documents containing either both `Hello` and `world` or documents that only contain `hello`. This is the `last` strategy, where words are stripped from the right.
The other strategy is `all`, where both `hello` and `worlds` **must** be present in a document for it to be returned.

// TODO: add documentation link

```js
{
matchingStrategy: 'all' // default last
}
```

## 🪡 Example with InstantSearch

The open-source [InstantSearch](https://www.algolia.com/doc/api-reference/widgets/js/) library powered by Algolia provides all the front-end tools you need to highly customize your search bar environment.
Expand Down
23 changes: 11 additions & 12 deletions src/adapter/search-request-adapter/__tests__/search-params.tests.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { adaptSearchParams } from '../search-params-adapter'
import { MatchingStrategies } from '../../../types'

const DEFAULT_CONTEXT = {
indexUid: 'test',
pagination: { paginationTotalHits: 20, page: 0, hitsPerPage: 6 },
defaultFacetDistribution: {},
finitePagination: false,
}

describe('Parameters adapter', () => {
test('adapting a basic searchContext ', () => {
const searchParams = adaptSearchParams({
...DEFAULT_CONTEXT,
finitePagination: false,
})

expect(searchParams.attributesToHighlight).toContain('*')
Expand All @@ -22,7 +23,6 @@ describe('Parameters adapter', () => {
...DEFAULT_CONTEXT,
facetFilters: [['genres:Drama', 'genres:Thriller'], ['title:Ariel']],
sort: 'id < 1',
finitePagination: false,
})

expect(searchParams.filter).toStrictEqual([
Expand All @@ -33,6 +33,15 @@ describe('Parameters adapter', () => {
expect(searchParams.attributesToHighlight).toContain('*')
expect(searchParams.attributesToHighlight?.length).toBe(1)
})

test('adapting a searchContext with matching strategy', () => {
const searchParams = adaptSearchParams({
...DEFAULT_CONTEXT,
matchingStrategy: MatchingStrategies.ALL,
})

expect(searchParams.matchingStrategy).toEqual('all')
})
})

describe('Geo rules adapter', () => {
Expand All @@ -42,7 +51,6 @@ describe('Geo rules adapter', () => {
facetFilters: [['genres:Drama', 'genres:Thriller'], ['title:Ariel']],
insideBoundingBox: '0,0,0,0',
sort: 'id < 1',
finitePagination: false,
})

expect(searchParams.filter).toStrictEqual([
Expand All @@ -60,7 +68,6 @@ describe('Geo rules adapter', () => {
...DEFAULT_CONTEXT,
facetFilters: [['genres:Drama', 'genres:Thriller'], ['title:Ariel']],
insideBoundingBox: '0,0,0,0',
finitePagination: false,
})

expect(searchParams.filter).toEqual([
Expand All @@ -77,7 +84,6 @@ describe('Geo rules adapter', () => {
...DEFAULT_CONTEXT,
insideBoundingBox: '0,0,0,0',
sort: 'id < 1',
finitePagination: false,
})

expect(searchParams.filter).toEqual(['_geoRadius(0.00000, 0.00000, 0)'])
Expand All @@ -90,7 +96,6 @@ describe('Geo rules adapter', () => {
const searchParams = adaptSearchParams({
...DEFAULT_CONTEXT,
insideBoundingBox: '0,0,0,0',
finitePagination: false,
})

expect(searchParams.filter).toEqual(['_geoRadius(0.00000, 0.00000, 0)'])
Expand Down Expand Up @@ -132,7 +137,6 @@ describe('Pagination adapter', () => {
test('adapting a searchContext with no finite pagination', () => {
const searchParams = adaptSearchParams({
...DEFAULT_CONTEXT,
finitePagination: false,
})

expect(searchParams.limit).toBe(7)
Expand All @@ -142,7 +146,6 @@ describe('Pagination adapter', () => {
const searchParams = adaptSearchParams({
...DEFAULT_CONTEXT,
pagination: { paginationTotalHits: 20, page: 1, hitsPerPage: 6 },
finitePagination: false,
})

expect(searchParams.limit).toBe(13)
Expand All @@ -152,7 +155,6 @@ describe('Pagination adapter', () => {
const searchParams = adaptSearchParams({
...DEFAULT_CONTEXT,
pagination: { paginationTotalHits: 20, page: 40, hitsPerPage: 6 },
finitePagination: false,
})

expect(searchParams.limit).toBe(20)
Expand All @@ -162,7 +164,6 @@ describe('Pagination adapter', () => {
const searchParams = adaptSearchParams({
...DEFAULT_CONTEXT,
pagination: { paginationTotalHits: 4, page: 0, hitsPerPage: 6 },
finitePagination: false,
})

expect(searchParams.limit).toBe(4)
Expand All @@ -173,7 +174,6 @@ describe('Pagination adapter', () => {
...DEFAULT_CONTEXT,
query: '',
pagination: { paginationTotalHits: 4, page: 0, hitsPerPage: 6 },
finitePagination: false,
placeholderSearch: false,
})

Expand All @@ -185,7 +185,6 @@ describe('Pagination adapter', () => {
...DEFAULT_CONTEXT,
query: '',
pagination: { paginationTotalHits: 200, page: 0, hitsPerPage: 6 },
finitePagination: false,
placeholderSearch: true,
})

Expand Down
7 changes: 7 additions & 0 deletions src/adapter/search-request-adapter/search-params-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export function MeiliParamsCreator(searchContext: SearchContext) {
finitePagination,
sort,
pagination,
matchingStrategy,
} = searchContext

return {
Expand Down Expand Up @@ -119,6 +120,11 @@ export function MeiliParamsCreator(searchContext: SearchContext) {
}
}
},
addMatchingStrategy() {
if (matchingStrategy) {
meiliSearchParams.matchingStrategy = matchingStrategy
}
},
}
}

Expand All @@ -144,6 +150,7 @@ export function adaptSearchParams(
meilisearchParams.addFilters()
meilisearchParams.addSort()
meilisearchParams.addGeoSearchRules()
meilisearchParams.addMatchingStrategy()

return meilisearchParams.getParams()
}
1 change: 1 addition & 0 deletions src/contexts/search-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
AlgoliaMultipleQueriesQuery,
SearchContext,
FacetDistribution,
MatchingStrategies,
} from '../types'

import { createPaginationContext } from './pagination-context'
Expand Down
7 changes: 7 additions & 0 deletions src/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,19 @@ export type ParsedFilter = {
value: string
}

export const enum MatchingStrategies {
ALL = 'all',
LAST = 'last',
}

export type InstantMeiliSearchOptions = {
paginationTotalHits?: number
placeholderSearch?: boolean
primaryKey?: string
keepZeroFacets?: boolean
finitePagination?: boolean
clientAgents?: string[]
matchingStrategy?: MatchingStrategies
}

export type SearchCacheInterface = {
Expand Down Expand Up @@ -79,6 +85,7 @@ export type SearchContext = Omit<InstantSearchParams, 'insideBoundingBox'> &
sort?: string
placeholderSearch?: boolean
primaryKey?: string
matchingStrategy?: MatchingStrategies
}

export type InstantMeiliSearchInstance = SearchClient & {
Expand Down