ほとんどのアプリでは、ユーザーがアプリのコンテンツを検索できるようになっています。たとえば、特定の単語を含む投稿や特定のトピックについて書いたメモを検索するケースなどが考えられます。
Cloud Firestore は、ネイティブ インデックスの作成やドキュメント内のテキスト フィールドの検索をサポートしていません。さらに、コレクション全体をダウンロードして、クライアントサイドでフィールドを検索することは現実的ではありません。
Cloud Firestore データの全文検索を有効にするには、専用のサードパーティの検索サービスを使用します。これらのサービスは、単純なデータベース クエリで利用できる機能をはるかに上回る、高度なインデックス作成と検索の機能を提供します。
続行する前に、以下の検索プロバイダを調査し、いずれかを選択してください。
ソリューション: 外部の検索サービス
各メモがドキュメントとして記録されているメモ作成アプリを見てみましょう。
// /notes/${ID}
{
owner: "{UID}", // Firebase Authentication's User ID of note owner
text: "This is my first note!"
}
Elastic と Cloud Functions を使用して、各メモのコンテンツのインデックスを登録し、検索を有効にすることができます。まず、Elastic インスタンス ID、ユーザー名、パスワードを使用して Elastic クライアントを構成します。
Node.js
const { Client } = require("@elastic/elasticsearch"); // Initialize Elastic, requires installing Elastic dependencies: // https://github.com/elastic/elasticsearch-js // // ID, username, and password are stored in functions config variables const ELASTIC_ID = functions.config().elastic.id; const ELASTIC_USERNAME = functions.config().elastic.username; const ELASTIC_PASSWORD = functions.config().elastic.password; const client = new Client({ cloud: { id: ELASTIC_ID, username: ELASTIC_USERNAME, password: ELASTIC_PASSWORD, } });
次に、メモが書き込まれるたびにインデックスを更新する関数を追加します。
Node.js
// Update the search index every time a blog post is written. exports.onNoteCreated = functions.firestore.document('notes/{noteId}').onCreate(async (snap, context) => { // Get the note document const note = snap.data(); // Use the 'nodeId' path segment as the identifier for Elastic const id = context.params.noteId; // Write to the Elastic index client.index({ index: "notes", id, body: note, }); });
データのインデックスが作成されたら、呼び出し可能な Cloud Functions の関数を使用してインデックスを検索します。
Node.js
exports.searchNotes = functions.https.onCall(async (data, context) => { const query = data.query; // Search for any notes where the text field contains the query text. // For more search examples see: // https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/search_examples.html const searchRes = await client.search({ index: "notes", body: { query: { query_string: { query: `*${query}*`, fields: [ "text" ] } } } }); // Each entry will have the following properties: // _score: a score for how well the item matches the search // _source: the original item data const hits = searchRes.body.hits.hits; const notes = hits.map(h => h["_source"]); return { notes: notes }; });
これで、Firebase SDK を使用して検索機能を呼び出すことができます。
ウェブ
const searchNotes = firebase.functions().httpsCallable('searchNotes'); searchNotes({ query: query }) .then((result) => { const notes = result.data.notes; // ... });
セキュリティの追加
元のソリューションは、すべてのメモをすべてのユーザーが検索しても問題ない場合にのみ有効です。しかし、多くのユースケースでは出力する結果を制限し、セキュリティを確保する必要があります。
この場合、最も簡単なセキュリティ対策としては、Cloud Functions の関数を呼び出すユーザーの uid
を確認し、owner
フィールドがそのユーザー ID に一致するメモのみが出力されるように検索を制限します。
Elastic には、検索インデックスにロールベースのアクセスを提供するために使用できる、さまざまな認証方式と認可方式も用意されています。詳細については、Elasticsearch の認証と認可を徹底解説をご覧ください。
制限事項
- 料金: Elastic Cloud には多くのサービス階層が用意されています。必ず料金ページにアクセスして、お客様のニーズに最適なオプションを選択してください。