Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

stratboy's avatar

How to keep mailisearch index updated including relations?

Hi, I have something like this in my Seed model:

    protected static function boot(){
        parent::boot();
        
        static::updated(function ($seed) {
            // should force meilisearch to reindex
            //if($seed->wasChanged('category_id')) $seed->searchable();
            if($seed->isDirty('category_id')) $seed->searchable();
        });

    }

    public function category():BelongsTo {
        return $this->belongsTo(Category::class);
    }

    public function toSearchableArray(){
        return [
            'id' => (int) $this->id,
            'name' => $this->name,
            'slug' => $this->slug,
            'description' => $this->description,
            'category_id' => (int) $this->category_id,
            'category' => [
                'name' => $this->category->name,
                'slug' => $this->category->slug,
            ]
        ];
    }

But when I change the category associated to a model, category.name and category.slug are not updated in the data I retrieve from mailisearch, while category_id IT IS correctly updated instead, and I can read it in the search results.

category.slug/name are always 'one step behind'. Meaning that:

  • if I created the model and associated with category A, then in the search the model will be found with category A

  • if I change the model's category association (say from category A to category B) and then search again, it will still be found associated with category A

  • if I update again the association, say with category C, it will be found associated with category B

Keep in mind that category_id is instead always up to date. Why?

0 likes
4 replies
LaryAI's avatar
Level 58

The issue you're experiencing is due to the fact that the toSearchableArray method is not being called after the related Category model is updated. This is because the searchable method is only being triggered when the Seed model itself is updated, not when the related Category model is updated.

To ensure that the Seed model is re-indexed in Meilisearch whenever the related Category model is updated, you need to listen for changes on the Category model and then trigger the searchable method on the related Seed models.

Here's a solution to achieve this:

  1. Add an observer to the Category model to listen for updates.
  2. In the observer, re-index the related Seed models.

First, create an observer for the Category model:

// app/Observers/CategoryObserver.php

namespace App\Observers;

use App\Models\Category;

class CategoryObserver
{
    public function updated(Category $category)
    {
        // Re-index all related Seed models
        foreach ($category->seeds as $seed) {
            $seed->searchable();
        }
    }
}

Next, register the observer in your AppServiceProvider:

// app/Providers/AppServiceProvider.php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\Models\Category;
use App\Observers\CategoryObserver;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        Category::observe(CategoryObserver::class);
    }
}

Finally, ensure that you have a relationship defined in the Category model to get the related Seed models:

// app/Models/Category.php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Category extends Model
{
    public function seeds()
    {
        return $this->hasMany(Seed::class);
    }
}

With this setup, whenever a Category model is updated, the updated method in the CategoryObserver will be triggered, which will then re-index all related Seed models in Meilisearch.

This should ensure that the category.name and category.slug fields in the search index are always up to date.

stratboy's avatar

I think Lary is not understanding my question: I need to only reindex a single model, when I update it and change its associated category. I'm not changing the Category model itself. I'm only saying that model1 belongs now to Category B instead of Category A.

stratboy's avatar
stratboy
OP
Best Answer
Level 5

Here's my own answer:

Currently at least on Laravel 11 (and v10 too I suppose), you can configure which related models to update before making the main model 'searchable', using the makeSearchableUsing() method.

https://laravel.com/docs/11.x/scout#modifying-records-before-importing

// Seed Model
use Illuminate\Database\Eloquent\Collection;

public function makeSearchableUsing(Collection $models): Collection{
    return $models->load('category')
}
1 like
binfask's avatar

@stratboy Thanks for this thread, hopefully you got the solution, but one of my application is still running on v9 . do you have any alternative option for it?

Please or to participate in this conversation.