Multiple models in one index
Aggregators
An Aggregator is a clean way to implement site-wide search in a single index with multiple entity types.
Defining Aggregators
To create a new aggregator, add a new class to your entities directory. The getEntities
method of this class should return all the entity classes you want to index:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Algolia\SearchBundle\Entity\Aggregator;
/**
* @ORM\Entity
*/
class News extends Aggregator
{
/**
* Returns the entities class names that should be aggregated.
*
* @return string[]
*/
public static function getEntities()
{
return [
Post::class,
Comment::class,
];
}
}
If you’re using a NoSQL database like MongoDB, you have to use the Algolia\SearchBundle\Document\Aggregator
class instead of Algolia\SearchBundle\Entity\Aggregator
.
Finally, add the new aggregator class name into the algolia_search.yml
file:
1
2
3
- indices:
- name: news
class: App\Entity\News
Searching
An aggregator is a standard entity class. You can begin searching entities on the aggregator using the search
method on your SearchService:
1
2
3
4
5
6
7
$this->searchService->index($objectManager, $post);
$this->searchService->index($objectManager, $comment);
$results = $this->searchService->search($objectManager, News::class, 'query');
// $results[0] contains a \App\Entity\Post.
// $results[1] contains a \App\Entity\Comment.
Be careful, the $result
array may contain different types of entities instances.
If you want to get the raw results from Algolia, use the rawSearch()
method. However, this time, each result may contain a different structure:
1
$results = $this->searchService->rawSearch(News::class, 'query');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"hits": [
{
"id": 1,
"title": "Article title",
"slug": "article-title",
"content": "Article content by query",
"objectID": "App\\Entity\\Article::1"
},
{
"id": 1,
"content": "Comment content by query",
"objectID": "App\\Entity\\Comment::1"
}
]
}
To ensure that each result has a similar structure, you may need to implement the method normalize
on each entity or override it on the aggregator class.
Conditional indexing
Conditional indexing on Aggregators works just like a normal entity, using the index_if
key. You may want to use $this->entity
to have access to the current entity being aggregated. Here is an example using the method approach:
1
2
3
4
- indices:
- name: news
class: App\Entity\News
index_if: isPublished
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* @ORM\Entity
*/
class News extends Aggregator
{
// ...
public function isPublished()
{
// Index only published articles.
if ($this->entity instanceof Article) {
return $this->entity->isPublished();
}
// If is not an article, index anyway.
return true;
}
}
For more information about conditional indexing, see Indexing conditionally.