I write api and use Laravel Scout + Meilisearch on my project. Everything is working. But I have some doubts about whether I am using meilisearch correctly. I would appreciate any help.
I know that it is possible to access meilisearch via localhost::7700 using Meilisearch\Client, as well as through the search method provided by the Searchable trait. In case I access it via the search method, like this:
$this->query = User::search($query, function ($meili_search, string $query, array $options) use ($request, $sort_field, $sort_direction) {
$options['offset'] = PaginatorHelper::offset($request->page ?? 1, $request->per_page);
$options['limit'] = intval($request->per_page);
$options['sort'] = [$sort_field .':' . $sort_direction];
return $meili_search->search($query, $options);
});
$this->query->get();
I see Eloquent queries in the telescope like:
select * from
userswhere
users.
id in (1, 2, 3)
But I don't understand why I see Eloquent queries if I request data via meilisearch? As if queries go to both meilisearch and mysql.
I expect data to be requested from meilisearch directly, bypassing Eloquent and the current behavior is confusing me.
Yes, you are using it correctly. When you use get(), first it gets ids from Meilisearch database and then call a query to the datable using whereIn.
You can take a look, this is code of get method https://github.com/laravel/scout/blob/10.x/src/Builder.php#L286
/**
* Get the results of the search.
*
* @return \Illuminate\Database\Eloquent\Collection
*/
public function get()
{
return $this->engine()->get($this);
}
It calls the get method of engine, in this case, MeilisearchEngine. MeilisearchEngine extends Engine. https://github.com/laravel/scout/blob/10.x/src/Engines/Engine.php#L133
/**
* Get the results of the given query mapped onto models.
*
* @param \Laravel\Scout\Builder $builder
* @return \Illuminate\Database\Eloquent\Collection
*/
public function get(Builder $builder)
{
return $this->map(
$builder, $this->search($builder), $builder->model
);
}
Within the map method, it calls getScoutModelsByIds method https://github.com/laravel/scout/blob/10.x/src/Engines/MeilisearchEngine.php#L264
* Map the given results to instances of the given model.
*
* @param \Laravel\Scout\Builder $builder
* @param mixed $results
* @param \Illuminate\Database\Eloquent\Model $model
* @return \Illuminate\Database\Eloquent\Collection
*/
public function map(Builder $builder, $results, $model)
{
if (is_null($results) || 0 === count($results['hits'])) {
return $model->newCollection();
}
$objectIds = collect($results['hits'])->pluck($model->getScoutKeyName())->values()->all();
$objectIdPositions = array_flip($objectIds);
return $model->getScoutModelsByIds(
$builder, $objectIds
)->filter(function ($model) use ($objectIds) {
return in_array($model->getScoutKey(), $objectIds);
})->sortBy(function ($model) use ($objectIdPositions) {
return $objectIdPositions[$model->getScoutKey()];
})->values();
}
Within getScoutModelsByIds, it calls getScoutModelsByIds: https://github.com/laravel/scout/blob/10.x/src/Searchable.php#L224
/**
* Get the requested models from an array of object IDs.
*
* @param \Laravel\Scout\Builder $builder
* @param array $ids
* @return mixed
*/
public function getScoutModelsByIds(Builder $builder, array $ids)
{
return $this->queryScoutModelsByIds($builder, $ids)->get();
}
And then, queryScoutModelsByIds builds query using whereIn:
/**
* Get a query builder for retrieving the requested models from an array of object IDs.
*
* @param \Laravel\Scout\Builder $builder
* @param array $ids
* @return mixed
*/
public function queryScoutModelsByIds(Builder $builder, array $ids)
{
$query = static::usesSoftDelete()
? $this->withTrashed() : $this->newQuery();
if ($builder->queryCallback) {
call_user_func($builder->queryCallback, $query);
}
$whereIn = in_array($this->getKeyType(), ['int', 'integer']) ?
'whereIntegerInRaw' :
'whereIn';
return $query->{$whereIn}(
$this->qualifyColumn($this->getScoutKeyName()), $ids
);
}
To get raw results just from Meilisearch, you can use raw method:
$this->query->raw();