#database #development #laravel #php

When you use Laravel Scout for full-text search, you can search on all attributes of a model. But what if you want to search on specific attributes? In this post, I'll show you how to do that.

I'm assuming you are using Meilisearch in as your full-text search engine. When you use a different engine, this trick will probably not work.

First, let's look at how the model we're using is setup. In my use-case, I'm having a Document class which contains both a searchable field name (the name of the document) and text (the actual text contents of the file).

To achieve, this, I've setup the following model:

app/Models/Document.php

 1namespace App\\Models;
 2
 3use Illuminate\Database\Eloquent\Model;
 4use Laravel\Scout\Searchable;
 5
 6final class Document extends Model
 7{
 8    use Searchable;
 9
10    public function searchableAs(): string
11    {
12        return 'documents_index';
13    }
14
15    public function toSearchableArray(): array
16    {
17        return [
18            'id' => $this->id,
19            'name' => $this->name,
20            'text' => $this->text,
21        ];
22    }
23}

In my Laravel scout configuration, I marked all of these attributes as searchable:

config/scout.php

 1return [
 2    'meilisearch' => [
 3        'host' => env('MEILISEARCH_HOST', 'http://localhost:7700'),
 4        'key' => env('MEILISEARCH_KEY', null),
 5        'index-settings' => [
 6            Document::class => [
 7                'filterableAttributes'=> ['id', 'name', 'text'],
 8                'sortableAttributes' => [],
 9            ],
10        ],
11    ],
12];

After configuring the search, don't forget to sync the index settings before you start adding items to the index (as described here):

1php artisan scout:sync-index-settings

I want to be able to search on both fields, it's simply doing:

1use App\\Models\\Document;
2
3Document::search($query)->get();

This will search on all attributes of the model. But what if I want to search on only the name attribute? You can do this by specifying the attributes you want to search on:

 1use App\\Models\\Document;
 2use Meilisearch\Endpoints\Indexes;
 3
 4Document::search(
 5    $searchQuery,
 6    function (Indexes $searchEngine, string $query, array $options) {
 7        $options['attributesToSearchOn'] = ['name'];
 8        return $searchEngine->search($query, $options);
 9    }
10)->get();

The function you specify in the search function allows you to customize the search options for this query. In this example, we used the option attributesToSearchOn to specify the attributes we want to search on. This will cause the search to only search on the name attribute.

You can also use this to search on multiple attributes:

 1use App\\Models\\Document;
 2use Meilisearch\Endpoints\Indexes;
 3
 4Document::search(
 5    $searchQuery,
 6    function (Indexes $searchEngine, string $query, array $options) {
 7        $options['attributesToSearchOn'] = ['name', 'text'];
 8        return $searchEngine->search($query, $options);
 9    }
10)->get();

Be careful though, attributes passed to attributesToSearchOn must also be present in the searchableAttributes list.

There are many more options you can pass on to a search query in Meilisearch. The full list can be found here.