Laravel Scout
Laravel Search: Laravel Scout
Categories:
Start Laravel Scout
Install Packages
composer require laravel/scout
php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"
Setting environment
# .env
SCOUT_DRIVER=database
SCOUT_PREFIX=scout
SCOUT_QUEUE=false
SCOUT_QUEUE_NAME=scout
Add the Laravel Scout to the Eloquent Model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;
class Post extends Model
{
use Searchable;
}
Define search columns
The toSearchableArray()
function is NOT necessary, but it will search all columns on the database table by default
Defining the specific search columns
is highly recommended to improve your search performance.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;
class Post extends Model
{
use Searchable;
/**
* Get the indexable data array for the model.
*
* @return array<string, mixed>
*/
public function toSearchableArray(): array
{
return [
'title' => $this->title,
'content' => $this->content,
'description' => $this->description,
];
}
}
Search the post via laravel scout
$search_text = 'taiwan';
$PostModelPaginate = Post::search($search_text)
->whereIn('status', ['published'])
->paginate(
perPage: 30,
page: 1
);
The search sql will looks like this on the PostgreSQL
select
*
from
"post"
where
(
"post"."title" :: text ilike '%taiwan%'
or "post"."content" :: text ilike '%taiwan%'
or "post"."description" :: text ilike '%taiwan%'
)
and "status" in ('published')
order by
"id" desc
limit
30 offset 0
Change laravel scout search query for columns
-
SearchUsingPrefix
will use theilike 'taiwan%'
to search the database instead of theilike '%taiwan%'
-
SearchUsingFullText
will use the full text search to search the database instead of theilike '%taiwan%'
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;
use Laravel\Scout\Attributes\SearchUsingFullText;
use Laravel\Scout\Attributes\SearchUsingPrefix;
class Post extends Model
{
use Searchable;
/**
* Get the indexable data array for the model.
*
* @return array<string, mixed>
*/
#[SearchUsingPrefix(['title', 'content'])]
#[SearchUsingFullText(['description'])]
public function toSearchableArray(): array
{
return [
'title' => $this->title,
'content' => $this->content,
'description' => $this->description,
];
}
}
We still use the same query to search the database
$search_text = 'taiwan';
$PostModelPaginate = Post::search($search_text)
->whereIn('status', ['published'])
->paginate(
perPage: 30,
page: 1
);
The search sql will looks like this on the PostgreSQL
select
*
from
"post"
where
(
"post"."title" :: text ilike 'taiwan%'
or "post"."content" :: text ilike 'taiwan%'
or (
to_tsvector(
'english', "post"."description"
)
) @@ plainto_tsquery('english', ?)
)
and "status" in ('published')
limit
30 offset 0
Update search database
Adding Records
use App\Models\Order;
$order = new Order;
// ...
$order->save();
Adding Records Via Query
use App\Models\Order;
Order::where('price', '>', 100)->searchable();
Updating Records
use App\Models\Order;
$order = Order::find(1);
// Update the order...
$order->save();
Removing Records
use App\Models\Order;
$order = Order::find(1);
$order->delete();
Order::where('price', '>', 100)->unsearchable();
Update search database with queue
You have to update the search database when you update your data.
But you can use queue
to update search database behind the scenes.
// config/scout.php
return [
'queue' => env('SCOUT_QUEUE', false),
]
// config/scout.php
return [
'queue' => [
'connection' => 'redis',
'queue' => 'scout'
],
]
Add the queue job to your artisan queue command
php artisan queue:work --queue=high,low,scout
Add macro count method to Laravel Scout
// app/Providers/AppServiceProvider.php
use Illuminate\Support\Facades\Response;
use Illuminate\Support\ServiceProvider;
use Laravel\Scout\Builder;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Builder::macro('count', function () {
return $this->engine()->getTotalCount(
$this->engine()->search($this)
);
});
}
use App\Models\Order;
Post::search('Taiwan')->count();