Concepts / Building Search UI / Multi index search
May. 10, 2019

Multi Index Search

You are reading the documentation for Angular InstantSearch v3, which is in beta. You can find the v2 documentation here.

Overview

It might happen that you want to search across multiple indices at the same time. InstantSearch.js has a built-in solution for searching into multiple indices with an autocomplete component. An another common use case is to display hits from multiple indices at the same time. We don’t have a proper API for this use case but we can synchronize two InstantSearch.js instance to have the same behavior.

In this guide we will learn how to share a single ais-search-box to display multiple hits from different indices. We will also take a look at how to create an autocomplete that targets multiple indices. The source code of both examples can be found on GitHub.

Hits from multiple indices

For this first use case we share a single input to search into multiple indices. For this behavior we use two ais-instantsearch instances. Each of them target a specific index, the first one is players and the second is actors.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// app.component.ts

const searchClient = algoliasearch(
  'latency',
  '6be0576ff61c053d5f9a3225e2a90f76'
);

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  private query : string = "";

  public configPlayers = {
    indexName: 'players',
    searchClient,
  };

  public configActors = {
    indexName: 'actors',
    searchClient,
  };

  onQuery($event) {
    this.query = $event.target.value
  }

  get searchParameters() {
    return {
      query: this.query
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!-- app.component.html -->
<input type="text" class="ais-SearchBox-input" (keyup)="onQuery($event)"/>

<ais-instantsearch [config]="configPlayers">
    <h3>Players</h3>
    <ais-configure [searchParameters]="searchParameters"></ais-configure>
    <ais-hits>
        <ng-template let-hits="hits" let-results="results">
            <ol class="ais-Hits-list">
                <li class="ais-Hits-item" *ngFor="let hit of hits">
                    <ais-highlight attribute="name" [hit]="hit"></ais-highlight>
                </li>
            </ol>
        </ng-template>
    </ais-hits>
</ais-instantsearch>

<ais-instantsearch [config]="configActors">
    <h3>Actors</h3>
    <ais-configure [searchParameters]="searchParameters"></ais-configure>
    <ais-hits>
        <ng-template let-hits="hits" let-results="results">
            <ol class="ais-Hits-list">
                <li class="ais-Hits-item" *ngFor="let hit of hits">
                    <ais-highlight attribute="name" [hit]="hit"></ais-highlight>
                </li>
            </ol>
        </ng-template>
    </ais-hits>
</ais-instantsearch>

What’s to note here is that we make use of a custom search box and inject the query into two instantsearch instances thanks to ais-configure component.

You can find the complete example on GitHub.

autocomplete

For this second use case we are gonna build an autocomplete to search into multiple indices. We are not going to talk too much about the autocomplete part. You can find a complete guide on the subject in the documentation. The autocomplete is built withA Angular Material’s Autocomplete and the autocomplete component. The only difference with the previous guide is how we append the hits to the autocomplete.

The ais-autocomplete component takes indices as a prop. This is an array of additional indices to do the search in, in this case the actors index.

First make sure you have the correct setup to use Angular Material’s components, then import MatInputModule and MatAutocompleteModule inside your project. ddf

$
ng add @angular/material
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NgModule } from '@angular/core';
import { NgAisModule } from 'angular-instantsearch';
import { MatInputModule, MatAutocompleteModule } from '@angular/material';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    NgAisModule.forRoot(),
    BrowserModule,
    BrowserAnimationsModule,

    MatInputModule,
    MatAutocompleteModule,
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Now create a new component autocomplete.component.ts inheriting from BaseWidget and connect it to your instant-search instance to autocomplete.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import { Component, Inject, forwardRef, Input } from '@angular/core';
import { BaseWidget, NgAisInstantSearch } from 'angular-instantsearch';
import { connectAutocomplete } from 'instantsearch.js/es/connectors';

@Component({
    selector: 'app-autocomplete',
    template: ``,
})
export class Autocomplete extends BaseWidget {
    state: {
        query: string;
        refine: Function;
        indices: object[];
    };

    constructor(
        @Inject(forwardRef(() => NgAisInstantSearch))
        public instantSearchParent
    ) {
        super('Autocomplete');
    }

    public ngOnInit() {
        this.createWidget(connectAutocomplete, {
            indices: [
                { value: "actors" } // adds index `actors` to search
            ]
        });
        super.ngOnInit();
    }
}

Now you just need to use Angular Material Autocomplete component and feed it with the data of our indices

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Component({
    selector: 'app-autocomplete',
    template: `
    <div>
      <input matInput [matAutocomplete]="auto" (keyup)="handleChange($event)" style="width: 100%; padding: 10px"/>
        <mat-autocomplete #auto="matAutocomplete" style="margin-top: 30px; max-height: 600px">
            <mat-optgroup *ngFor="let index of (state.indices || [])" [label]="index.index">
                <mat-option *ngFor="let options of index.hits" [value]="options.name">
                    <div>
                        {{options.name}}
                    </div>
                </mat-option>
            </mat-optgroup>
        </mat-autocomplete>
    </div>
    `,
})
export class Autocomplete extends BaseWidget { /* ... */ }

Now Let’s use our newly created Autocomplete component in our code.

1
2
3
4
5
6
  <ais-instantsearch [config]="config">
    <ais-configure [searchParameters]="{hitsPerPage: 3}"></ais-configure>
    <div class="container">
      <app-autocomplete></app-autocomplete>
    </div>
  </ais-instantsearch>

Our Autocomplete component is now searching in two indices: players (the primary index) and actors.

You can find the complete example on GitHub.

Did you find this page helpful?