peirix
peirix

Reputation: 37771

Custom sort in Laravel Scout search (Algolia)

I'm using the Laravel Algolia package for my search, and I would like to tap into the sorting order before sending my results to the view. After searching for all products I would like to bump up all products that the user has in their favourites. And then finally paginate the results.

$results = Product::search($search);
//Then I would like to do this:
$results = $results->sort(function($a, $b) {
  return $user->hasFavourite($a) < $user->hasFavourite($b) ? -1 : 1
});
return $results->paginate(48);

But I know this isn't allowed in the Laravel\Scout\Builder object that is returned from the ::search, so I was wondering if there's a way around this?

Upvotes: 1

Views: 994

Answers (1)

Alijvhr
Alijvhr

Reputation: 2263

Add relationship in scout

As mentioned in this blog post, you have to add the relationship to the model first! You can do it in any way you know better:

public function userRanks()
    {
        return $this->hasMany('App\Models\Favorties', 'id', 'user_id');
    }

Searchable by relationship

Then You should make model searchable by that index:

protected function makeAllSearchableUsing($query)
{
    return $query->with('userRanks');
}

Make Sortable

Add created field to sortables! as mentioned in documentation:

'index-settings' => [
    Product::class => [
        'sortableAttributes' => ['userRanks']
    ],
],

ReIndex(optional)

If you already have records in your index, make sure that you re-index with Meilisearch.

If you don’t have a ton of data, you could flush and re-build the entire index using the following commands:

// Clear the index
php artisan scout:flush "App\Models\Product"

// Re-populate the index
php artisan scout:import "App\Models\Product"

Replicas

Read the docs:

By design, Algolia provides one ranking formula per index: when you want to provide different rankings for the same data you need to use different indices for each ranking. These additional indices are called replicas.

Based On docs this will help:

$index->setSettings([
  'replicas' => [
    'virtual(products_virtual_price_desc)'
  ]
]);
$replica_index = $client->initIndex('products_virtual_price_desc');

$replica_index->setSettings([
  'customRanking' => [
    'desc(price)'
  ]
]);

Upvotes: 0

Related Questions