A helper library for meilisearch-js that provides convenient utility methods to simplify common operations and enhance your Meilisearch experience.
npm install meilisearch-helperThere are two ways to build a MeiliSearch filter:
- Use the
buildMeiliSearchFilterfunction to build a filter from a MongoDB-style filter object. - Use the
MeiliSearchFilterBuilderclass to build a filter with a fluent API.
Note:
CONTAINSandSTARTS WITHare experimental features. Use the experimental features endpoint to enable them. More details can be found in the MeiliSearch documentation.
import { buildMeiliSearchFilter } from 'meilisearch-helper';
type FilterableAttributes = 'name' | 'age' | 'isStudent';
const filter = buildMeiliSearchFilter<FilterableAttributes>({
$or: [
{ $or: [{ name: 'John' }, { name: 'Doe' }] },
{ $and: [{ age: { $gt: 18 } }, { isStudent: true }] },
],
age: { $lt: 30 },
$geoRadius: {
lat: 45.472735,
lng: 9.184019,
distanceInMeters: 2000,
},
});
console.log(filter);
// => ((name = "John" OR name = "Doe") OR age > 18 AND isStudent = true) AND age < 30 AND _geoRadius(45.472735, 9.184019, 2000)Supported operators:
$eq: Equal, e.g.{ name: { $eq: 'John' } }=>name = "John"{ name: 'John' }=>name = "John"
$ne: Not equal, e.g.{ name: { $ne: 'John' } }=>name != "John"
$gt: Greater than, e.g.{ age: { $gt: 18 } }=>age > 18
$gte: Greater than or equal, e.g.{ age: { $gte: 18 } }=>age >= 18
$lt: Less than, e.g.{ age: { $lt: 18 } }=>age < 18
$lte: Less than or equal, e.g.{ age: { $lte: 18 } }=>age <= 18
$in: In, e.g.{ name: { $in: ['John', 'Doe'] } }=>name IN ["John", "Doe"]{ name: ['John', 'Doe'] }=>name IN ["John", "Doe"]
$nin: Not in, e.g.{ name: { $nin: ['John', 'Doe'] } }=>name NOT IN ["John", "Doe"]
$exists: Exists, e.g.{ name: { $exists: true } }=>name EXISTS{ name: { $exists: false } }=>name NOT EXISTS
$empty: Empty, e.g.{ name: { $empty: true } }=>name IS EMPTY{ name: { $empty: false } }=>name IS NOT EMPTY
$between: Between, e.g.{ age: { $between: [18, 30] } }=>age 18 TO 30
$contains: (Experimental) Contains, e.g.{ name: { $contains: 'John' } }=>name CONTAINS "John"
$notContains: (Experimental) Not contains, e.g.{ name: { $notContains: 'John' } }=>name NOT CONTAINS "John"
$startsWith: (Experimental) Starts with, e.g.{ name: { $startsWith: 'John' } }=>name STARTS WITH "John"
$notStartsWith: (Experimental) Not starts with, e.g.{ name: { $notStartsWith: 'John' } }=>name NOT STARTS WITH "John"
$or: Or, e.g.{ $or: [{ name: 'John' }, { name: 'Doe' }] }=>(name = "John" OR name = "Doe")
$and: And, e.g.{ $and: [{ age: { $gt: 18 } }, { isStudent: true }] }=>age > 18 AND isStudent = true
$geoRadius: Geo radius, e.g.{ $geoRadius: { lat: 45.472735, lng: 9.184019, distanceInMeters: 2000 } }=>_geoRadius(45.472735, 9.184019, 2000)
$geoBoundingBox: Geo bounding box, e.g.{ $geoBoundingBox: { topRight: { lat: 45.472735, lng: 9.184019 }, bottomLeft: { lat: 45.472735, lng: 9.184019 } } }=>_geoBoundingBox([45.472735, 9.184019], [45.472735, 9.184019])
More examples can be found in the tests.
Simple example:
import { MeiliSearchFilterBuilder } from 'meilisearch-helper';
type Person = {
name: string;
age: number;
isStudent: boolean;
};
type FilterableAttributes = keyof Person;
function buildFilter(query: Partial<Person>) {
let builder = new MeiliSearchFilterBuilder<FilterableAttributes>();
if (query.name) {
builder = builder.where('name', '=', query.name); // MeiliSearchFilterBuilder is immutable, you must re-assign!
}
if (query.age) {
builder = builder.where('age', '=', query.age);
}
if (query.isStudent) {
builder = builder.where('isStudent', '=', query.isStudent);
}
return builder.build();
}
console.log(buildFilter({ name: 'John', age: 20, isStudent: true }));
// => name = "John" AND age = 20 AND isStudent = trueComplex example:
import { MeiliSearchFilterBuilder } from 'meilisearch-helper';
type FilterableAttributes = 'name' | 'age' | 'isStudent';
// eb is a function to build a simple filter expression, more details below
const filter = new MeiliSearchFilterBuilder<FilterableAttributes>()
.where((eb) =>
eb.or([
eb.or([eb('name', '=', 'John'), eb('name', '=', 'Doe')]),
eb.and([eb('age', '>', 18), eb('isStudent', '=', true)]),
]),
)
.where('age', '<', 30)
.where((eb) => eb.geoRadius(45.472735, 9.184019, 2000))
.build();
console.log(filter);
// => ((name = "John" OR name = "Doe") OR age > 18 AND isStudent = true) AND age < 30 AND _geoRadius(45.472735, 9.184019, 2000)eb (expression builder): A function to build a simple filter expression.
eb(lhs: FilterableAttributes, operator: FilterBuilderOperator, rhs: BaseValueTypes | BaseValueTypes[]): string: Build a simple filter expression.
eb('age', '>', 18); // => age > 18eb.or(expressions: string[]): string: Combine multiple expressions withOR.
eb.or([eb('age', '>', 18), 'isStudent = true']); // => (age > 18 OR isStudent = true)eb.and(expressions: string[]): string: Combine multiple expressions withAND
eb.and([eb('age', '>', 18), 'isStudent = true']); // => age > 18 AND isStudent = trueeb.geoRadius(lat: number, lng: number, distanceInMeters: number): string: Build a geo radius filter expression.
eb.geoRadius(45.472735, 9.184019, 2000); // => _geoRadius(45.472735, 9.184019, 2000)eb.geoBoundingBox(topRight: { lat: number; lng: number }, bottomLeft: { lat: number; lng: number }): string: Build a geo bounding box filter expression.
eb.geoBoundingBox(
{ lat: 45.472735, lng: 19.184019 },
{ lat: 25.472735, lng: 9.184019 },
); // => _geoBoundingBox([45.472735, 19.184019], [25.472735, 9.184019])supported operators:
=: Equal, e.g..where('name', '=', 'John')=>name = "John"
!=: Not equal, e.g..where('name', '!=', 'John')=>name != "John"
>: Greater than, e.g..where('age', '>', 18)=>age > 18
>=: Greater than or equal, e.g..where('age', '>=', 18)=>age >= 18
<: Less than, e.g..where('age', '<', 18)=>age < 18
<=: Less than or equal, e.g..where('age', '<=', 18)=>age <= 18
in: In, e.g..where('name', 'in', ['John', 'Doe'])=>name IN ["John", "Doe"]
nin: Not in, e.g..where('name', 'nin', ['John', 'Doe'])=>name NOT IN ["John", "Doe"]
exists: Exists, e.g..where('name', 'exists', true)=>name EXISTSor.where('name', 'exists', false)=>name NOT EXISTS
empty: Empty, e.g..where('name', 'empty', true)=>name IS EMPTYor.where('name', 'empty', false)=>name IS NOT EMPTY
between: Between, e.g..where('age', 'between', [18, 30])=>age 18 TO 30
contains: (Experimental) Contains, e.g..where('name', 'contains', 'John')=>name CONTAINS "John"
notContains: (Experimental) Not contains, e.g..where('name', 'notContains', 'John')=>name NOT CONTAINS "John"
startsWith: (Experimental) Starts with, e.g..where('name', 'startsWith', 'John')=>name STARTS WITH "John"
notStartsWith: (Experimental) Not starts with, e.g..where('name', 'notStartsWith', 'John')=>name NOT STARTS WITH "John"
More examples can be found in the tests.
Build a MeiliSearch sort from an object.
import { buildMeiliSearchSort } from 'meilisearch-helper';
type SortableAttributes = 'name' | 'age';
const sort = buildMeiliSearchSort<SortableAttributes>({
name: 1,
age: -1,
_geoPoint: { lat: 48.8561446, lng: 2.2978204, direction: 1 },
});
console.log(sort);
// => [ "name:asc", "age:desc", "_geoPoint(48.8561446, 2.2978204):asc" ]More examples can be found in the tests.
Supported directions:
- Ascending:
1,asc,ascending - Descending:
-1,desc,descending
MIT