> ## Documentation Index
> Fetch the complete documentation index at: https://algolia.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Multiple models in one index

> How to implement aggregators to handle multiple models in one index using Laravel Scout with Algolia Scout Extended.

To search in multiple models at the same time, use aggregators.
Aggregators let you index multiple models in a single index.
They listen for updates in your models to automatically keep everything in sync.

## Create an aggregator

To create a new aggregator,
use the `scout:make-aggregator` Artisan command.
This command creates a new aggregator class in the `app/Search` directory:

```sh Command line icon=square-terminal theme={"system"}
php artisan scout:make-aggregator News
```

After generating your aggregator,
you should fill in the `$models` property of the class to identify the models to aggregate:

```php PHP icon=code theme={"system"}
namespace App\Search;

use Algolia\ScoutExtended\Searchable\Aggregator;

class News extends Aggregator
{
    /**
     * The names of the models that should be aggregated.
     *
     * @var string[]
     */
    protected $models = [
         \App\Event::class,
         \App\Article::class,
    ];
}
```

To register an Aggregator, use the `bootSearchable` method on the aggregator you want to register.
For this, you should use the `boot` method of one of your service providers.
The following example registers the aggregator in the `App\AppServiceProvider`:

```php PHP icon=code theme={"system"}
namespace App\Providers;

use App\Search\News;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        News::bootSearchable();
    }
}
```

When you use a model in multiple aggregators, by default Scout Extended registers one observer per model per aggregator.
This can result in twice the amount of indexing jobs when you update a model.
To ensure a single observer gets registered you have to boot all your aggregators using the `Aggregator::bootSearchables` method, passing your aggregator classes as argument:

```php PHP icon=code theme={"system"}
namespace App\Providers;

use App\Search\Article;
use App\Search\PremiumArticle;
use Algolia\ScoutExtended\Searchable\Aggregator;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Aggregator::bootSearchables([
          Article::class,
          PremiumArticle::class,
        ]);
    }
}
```

## Conditionally sync an aggregator

For `Searchable` models, you can use the [`shouldBeSearchable`](/doc/framework-integration/laravel/indexing/import-into-algolia#conditional-model-sync) method to conditionally change which results you want to index.
For aggregators, you can define a `shouldBeSearchable` method that calls the `shouldBeSearchable` method of the aggregated model.

```php PHP icon=code theme={"system"}
namespace App\Search;

use Algolia\ScoutExtended\Searchable\Aggregator;
use Laravel\Scout\Searchable;

class News extends Aggregator
{
    /**
     * The names of the models that should be aggregated.
     *
     * @var string[]
     */
    protected $models = [
         \App\Event::class,
         \App\Article::class,
    ];

    public function shouldBeSearchable()
    {
        // Check if the class uses the Searchable trait before calling shouldBeSearchable
        if (array_key_exists(Searchable::class, class_uses($this->model))) {
            return $this->model->shouldBeSearchable();
        }
    }
}
```

You can change the logic of your aggregator's `shouldBeSearchable` method with any condition that doesn't depend on its grouped models.

## Search an aggregator

An aggregator is a standard `Searchable` class.
You can search models on the aggregator using the `search` method:

```php PHP icon=code theme={"system"}
$models = App\Search\News::search('Star Trek')->get();

echo get_class($models[0]); // "App\Article"
echo get_class($models[1]); // "App\Comment"
```

<Check>
  Be careful, the `$models` array may contain different types of models instances.
</Check>

If you want to get the raw results from Algolia, use the `raw` method.
Be aware that each result may contain a different structure when using this method:

```php PHP icon=code theme={"system"}
$results = App\Search\News::search('Star Trek')->raw();
```

```json JSON icon=braces theme={"system"}
{
  "hits": [
    {
      "id": 1,
      "title": "Article title",
      "slug": "article-title",
      "content": "Article content",
      "objectID": "App\\Article::1"
    },
    {
      "id": 1,
      "content": "Comment content",
      "objectID": "App\\Comment::1"
    }
  ]
}
```

To ensure that each result have a similar structure,
you might need to implement the method `toSearchableArray` on the
each `Searchable` classes or directly on the aggregator class.

## Eager loading relationships

Sometimes you may want to eager load a relationship of an aggregated model.
To eager load relationships, use the property `$relations` of your aggregator class.
For example:

```php PHP icon=code theme={"system"}
class News extends Aggregator
{
    /**
     * The names of the models that should be aggregated.
     *
     * @var string[]
     */
    protected $models = [
         \App\Event::class,
         \App\Article::class,
    ];

    /**
     * Map of model relations to load.
     *
     * @var string[]
     */
    protected $relations = [
        \App\Event::class => ['user'],
        \App\Article::class => ['photo', 'user'],
    ];
}
```

## Turning off syncing per model

By default, the aggregator creates one aggregated index (in this case, "news").
But, Laravel Scout also still indexes the `Article` and `Event` models in their own "articles" and "events" indices.

To stop this, turn off indexing for these models globally.
In your `AppServiceProvider`, add the following:

```php PHP icon=code theme={"system"}
Laravel\Scout\ModelObserver::disableSyncingFor(Article::class);
Laravel\Scout\ModelObserver::disableSyncingFor(Event::class);
```

You can't use the [`shouldBeSearchable`](/doc/framework-integration/laravel/indexing/import-into-algolia#conditional-model-sync)
method in this case because the method doesn't know about the destination index.

<Info>
  The `scout:import command` doesn't take calls to `disableSearchSyncing` into account. Disabling search syncing only applies to updates to models made by the application, and not to bulk import operations through the `scout:import` command.
</Info>
