くらげになりたい。

くらげのようにふわふわ生きたい日曜プログラマなブログ。趣味の備忘録です。

Nuxt+Firebase+Algoliaで検索機能をつくってみた

開発しているWebサービスでユーザ検索機能を作ってみたときの備忘録。
Algoliaつかうとすぐできた(´ω`)

流れ

大まかな流れはこんな感じ。

  1. Algoliaのアカウント作成
  2. Algoliaのコンソールでインデックスを作成
  3. 検索したい初期データを登録する
  4. Algoliaのコンソールで検索対象のフィールドを設定
  5. Webサービス側で検索処理を実装
  6. Cloud FunctionsのFirestoreトリガーで連動処理を実装

アカウント作成やインデックスの作成とかは省略。。
ライブラリを使った検索やFirestoreとの連動部分のまとめ。

インストール

ライブラリが用意されているので、まずはインストール

$ npm install algoliasearch

# TypeScriptの型定義
$ npm install -D @types/algoliasearch

検索したいデータを登録する

とりあえず、初期データを登録するためのスクリプトを用意。
実行すると、Algoliaのコンソールに反映されるので、確認してみる。

ALGOLIA_APP_IDとかは、Algoliaのコンソールの「API Key」で確認できる。
登録とかもしたい時は、Admin API Keyの方を使う。

import algoliasearch from "algoliasearch";

async function main() {
  const ALGOLIA_APP_ID = "...";
  const ALGOLIA_API_KEY = "...";
  const ALGOLIA_INDEX_NAME = "...";

  // クライアントの初期化
  const client = algoliasearch(ALGOLIA_APP_ID, ALGOLIA_API_KEY);
  
  // インデックスの取得
  const index = client.initIndex(ALGOLIA_INDEX_NAME);

  // 検索したいデータ
  const users = [
    { uid: "...", name: "..." },
    { uid: "...", name: "..." }
  ];
  // objectIDを設定
  const data = users.map((v) => Object.assign(v, { objectID: v.uid }));

  // Algoliaに登録
  await index.saveObjects(data);
}

main().then();

ガイドも用意されているので、一読しておくといい感じ。

Importing with the API | How to | Sending and Managing Data | Guide | Algolia Documentation

注意点として、Algolia上のIDはobjectIDという名前ということ
このフィールドがないと自動生成してくれるけど、更新時に必要なので、あらかじめ設定しておく。
FirestoreならDocumentのIDとかでもいいかも。

検索する

Algoliaのコンソールで「Indices > Configuration > Searchable attributes」に移動して、検索対象のフィールドを設定。

設定が終わったら、とりあえず、スクリプトで検索してみる。
検索だけの時は、Search-Only API Keyの方を使う。

// 検索だけならalgoliasearch/liteを使う
import algoliasearch from "algoliasearch/lite";

async function main() {
  const ALGOLIA_APP_ID = "...";
  const ALGOLIA_API_KEY = "..."; // ※ API KeyはSearchOnlyのもの!!
  const ALGOLIA_INDEX_NAME = "...";

  // 初期化は同じ感じ
  const client = algoliasearch(ALGOLIA_APP_ID, ALGOLIA_API_KEY);
  const index = client.initIndex(ALGOLIA_INDEX_NAME);

  // 検索する
  const res = await index.search("検索ワード", {
    attributesToHighlight: [],
    responseFields: ["hits", "page", "hitsPerPage", "query", "nbHits", "nbPages"],
  });
  console.info(`res=${JSON.stringify(res, null, 2)}`);
}

main().then();

検索に関するAPI Referenceはこのあたり。
Search | API Reference | Algolia Documentation

あとは、検索部分をWebサービスに埋め込めばOK。
API KEYの種類を間違えないように確認が大事

FunctionsとAlgoliaを連動させる

検索ができたので、データがわかったときに連動するようにしていく。

CloudFunctionsにFirestoreのトリガーがあるので、
追加/変更/削除が発生したら、Algoliaのライブラリを呼び出すようにして連動させる。

環境変数を設定する

まずはCloudFunctionsの環境変数を設定する。

# 環境変数を設定。API_KEYはAdmin用のを使う
$ firebase functions:config:set algolia.app_id="..."
$ firebase functions:config:set algolia.api_key="..."
$ firebase functions:config:set algolia.index_name="..."

# 確認
$ firebase functions:config:get
# {
#   "algolia": {
#     "app_id": "..."
#     "api_key": "...",
#     "index_name": "...",
#   }
# }

Cloud FunctionsのFirestoreトリガーで連動処理を実装

こんな感じ。onWriteを使って、追加/変更/削除を1関数で実装してる。

import * as functions from "firebase-functions";
import algoliasearch, { SearchClient, SearchIndex } from "algoliasearch";

export default functions
  .runWith({ timeoutSeconds: 540, memory: "512MB" })
  .firestore.document(`users/{uid}`)
  .onWrite(async (change, context) => {
    const uid = context.params.uid;
    const oldData = change.before.data() | undefined;
    const newData = change.after.data() | undefined;

    // Algolia Clientの初期化
    const ALGOLIA_APP_ID = functions.config().algolia.app_id;
    const ALGOLIA_API_KEY = functions.config().algolia.api_key;
    const client = algoliasearch(ALGOLIA_APP_ID, ALGOLIA_API_KEY);
    
    // Algolia Indexの取得
    const ALGOLIA_INDEX_NAME = functions.config().algolia.index_name;
    const index = this.client.initIndex(ALGOLIA_INDEX_NAME);
    
    if (!!newData) {
      // 追加時/更新時: objectIDを追加して保存
      const data = Object.assign(newData, { objectID: uid });
      await index.saveObject(data);
      
    } else if (!!oldData) {
      // 削除時: objectIDに設定しているUIDを指定して削除
      await this.index.deleteObject(uid);
    }
  });

これでFirestoreの変更に応じて、Algoliaのインデックスを更新してくれる。

Indexの操作に関するAPI Referenceはこのあたり。
Indexing | API Reference | Algolia Documentation

1万レコードまでは無料なので、すごく増えるものでなければ、よさげ(´ω`)

参考にしたサイトさま