'Laravel Scout/Meilisearch - filter by a non-searchable column
I want to make it so that I can filter results based on a column that isn't searchable with Meilisearch and Laravel scout.
So imagine a "Comment" table, with the following searchable columns:
public function toSearchableArray() {
$array = Arr::only(
$this->toArray(),
['id','title', 'link', 'raw_text', 'subchan', 'nsfw']
);
return $array;
}
But only get results past a certain date:
Comment::search($query, ['filters' => 'created_at > 795484800'])
To do this, I need to add created_at
scout's toSearchableArray. The problem with this is that when a user searches, results from created_at
will also be queried.
Solution 1:[1]
If I understand you correctly you want to be able to filter based on the created_at
column, but it shouldn't be searchable, ie entering "795" as a query shouldn't return all results where "795" is part of the timestamp?
I don't think Scout will allow you to achieve this in a simple way at the moment but it should still be possible.
Step 1 is to add the created_at
column to the toSearchableArray()
method. This will ensure the data is indexed by Meili.
Step 2 is to alter the configuration of the index where your model is searchable in order to exclude created_at
from the list of searchable attributes. This is psuedo code and undocumented but it should look something like this:
$dummy = new Comment();
// Should resolve to an engine: https://github.com/laravel/scout/blob/f8aa3c3182fe97f56a6436fd0b28fcacfcbabc11/src/Searchable.php#L279
$engine = $dummy->searchableUsing();
// Should resolve to MeiliSearch\Endpoints\Indexes via a magic method that resolves the underlying Meili driver:
// https://github.com/laravel/scout/blob/33bbff0e3bfb1abd0ea34236c331fc17cdeac0bc/src/Engines/MeiliSearchEngine.php#L298
// ->
// https://github.com/meilisearch/meilisearch-php/blob/f25ee49b658f407af3d3f1f9a402997e7974b6bb/src/Delegates/HandlesIndex.php#L23
$index = $engine->index($dummy->searchableAs());
// https://github.com/meilisearch/meilisearch-php/blob/f25ee49b658f407af3d3f1f9a402997e7974b6bb/src/Endpoints/Delegates/HandlesSettings.php#L55
$index->updateSearchableAttributes(
['id','title', 'link', 'raw_text', 'subchan', 'nsfw']
);
Once created_at
is indexed but not searchable you want to filter on the value. Meili has operators for numeric values.
Step 3 is to do a custom search using Scout:
Comment::search($query, function (Indexes $meilisearch, $query, $options) {
$options['filters'] = 'created_at>795484800';
return $meilisearch->search($query, $options);
});
Again, this is pseudo code – I haven't tested any part of it. I would really appreciate if Scout would implement support for customizing the index' settings on creation or exposing a method for updating the settings, allowing you to add driver specific settings in your configuration file for example.
Solution 2:[2]
I solved my problem by using filterable attributes of Meilisearch. But it needs to be configured before running the search. I used php artisan tinker
to solve this as follows, you might want to write an artisan command to do so.
$client = new MeiliSearch\Client('https://url_to_meilisearch_instance:7700');
$client->index('comments_index')->updateFilterableAttributes(['created_at']); // Replace your index_name
And that's about it. If you have a rather large dataset, you might want to run the following command to check the status:
$client->index('comments_index')->stats();
If the response contains isIndexing => false
you're good to go. Now you may run the filter as usual,
Comment::search($query)->where('created_at', '>', 795484800)->get();
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | DharmanBot |