import 'package:meilisearch/meilisearch.dart';
// Create client instancefinal client = MeiliSearchClient('https://your-url.com', 'your_api_key');
// Target a specific indexfinal index = client.index('movies');
// Adds new or overwrites existing documents (by matching 'id')await index.addDocuments([
{'id': '1', 'title': 'Avatar', 'year': 2009},
{'id': '2', 'title': 'Gladiator', 'year': 2000},
]);
// Partially updates fields of existing documentsawait index.updateDocuments([
{'id': '1', 'year': 2010},
]);
| Operation | Code |
|---|---|
| Get one document by ID | var doc = await index.getDocument('1'); |
| Get a paginated list of documents | var docs = await index.getDocuments(params: GetDocumentsQuery(limit: 20, offset: 0)); |
| Delete single document | await index.deleteDocument('1'); |
| Delete multiple documents | await index.deleteDocuments(['1', '2']); |
| Delete all documents in index | await index.deleteAllDocuments(); |
var result = await index.search('avatar');
for (var hit in result.hits ?? []) {
print(hit['title']);
}
var result = await index.search(
'gladiator',
SearchQuery(
limit: 10,
offset: 0,
// Filter results (requires setting up filterableAttributes first)
filter: 'year > 2000 AND genre = "Action"',
// Sort results (requires setting up sortableAttributes first)
sort: ['year:desc'],
// Highlight matching text patterns
attributesToHighlight: ['title'],
),
);
- Note: Change these settings on your administrative backend or during app setup, not on every search query.
// Enable fields for filtering and sortingawait index.updateSettings(IndexSettings(
filterableAttributes: ['year', 'genre'],
sortableAttributes: ['year'],
rankingRules: [
'words',
'typo',
'proximity',
'attribute',
'sort',
'exactness',
],
));
- Write operations in Meilisearch (like adding or updating documents) are asynchronous.
- They return a Task object immediately while the server processes the request in the background.
// 1. Get task information from an operation
TaskInfo taskInfo = await index.addDocuments([...]);
// 2. Wait for the server to finish processing it
TaskResult finishedTask = await client.waitForTask(taskInfo.uid!);
// 3. Verify successif (finishedTask.status == 'succeeded') {
print('Documents added successfully!');
} else {
print('Error: ${finishedTask.error?.message}');
}
// Create a new index explicitlyawait client.createIndex('books', primaryKey: 'isbn');
// List all indexes
List<MeiliSearchIndex> indexes = await client.getIndexes();
// Delete an index completelyawait client.deleteIndex('books');
- The easiest way to implement typo tolerance in
- Meilisearch is built specifically for “search-as-you-type” storefronts and apps, so typo tolerance is enabled by default for every index and query. You do not need to pass any special flags or parameters in your Flutter code.
- It calculates the Levenshtein distance automatically, scaling the number of allowed typos based on the length of the query word:
1โ4characters:0typos allowed (strictly prefix matching).5โ8characters:1typo allowed.9+characters:2typos allowed (the maximum cap).
- If you need to change these default lengths (e.g., allow 1 typo on a 4-letter word), or disable typos entirely for specific attributes like SKU numbers, use the index settings via the Flutter SDK:
final index = client.index('products');
await index.updateTypoTolerance(TypoTolerance(
enabled: true,
// Change word length thresholds
minWordSizeForTypos: MinWordSizeForTypos(
oneTypo: 4, // 1 typo allowed if the word is 4+ characters
twoTypos: 8, // 2 typos allowed if the word is 8+ characters
),
// Disable typo checking on specific fields (e.g., serial numbers)
disableOnAttributes: ['sku_code', 'phone_number'],
));
- Yes, Meilisearch has a highly sophisticated, open-source, built-in multilingual tokenizer called Charabia.
- When you push a collection of documents or type a search string, Meilisearch runs it through Charabia automatically before it ever hits the database.
- You don’t have to break your strings or pass string arrays manually.
- Word Segmentation:
- It knows how to break sentences into tokens.
- For Western languages (Latin script), it splits on spaces, punctuation, and hyphens.
- For languages that don’t use spaces (like Japanese, Chinese, or Thai), it uses dictionary-based pipelines to intelligently extract actual words.
- Normalization:
- It converts all tokens to lowercase, removes accents/diacritics (e.g., converting
crรจmetocreme), and unifies casing. - This is why searches are case-insensitive by default.
CamelCase&SnakeCaseSeparation:
It automatically tokenizes terms like MeiliSearch into meili and search, or
flutter_appintoflutterandapp.Because tokenization is completely managed on the Meilisearch server engine, your Flutter code stays extremely clean.
You simply pass raw string text directly from your TextField into the index.search(‘raw text here’) function.
- How it works: All searches are entirely case-insensitive by default.
- Example: Querying FLUTTER, flutter, or FlUtTeR will return the exact same database records without any configuration