Skip to content
Permalink
Fetching contributors…
Cannot retrieve contributors at this time
196 lines (134 sloc) 6.87 KB
title lastmod publishdate author draft description tags youtube github
Algolia Fulltext Search Cloud Functions
2019-08-25 10:43:13 -0700
2019-08-25 10:43:13 -0700
Jeff Delaney
false
Build a pipeline for full-text search indexing with Firestore Cloud Functions
node
algolia
firestore
cloud-functions
mvp
dTXzxSlhTDM

One of the most commonly encountered limitations of Cloud Firestore (and GCP) is full-text search. This functionality is essential if you need to query complex text patterns in a database or filter results by multiple dynamic properties. My favorite solution to this limitation is Algolia, which provides a powerful, developer-friendly, search & discovery API. In the following lesson you will learn how to sync your Firestore data to an Algolia index via Cloud Functions.

{{< figure src="img/algolia-firestore-demo.png" caption="Notice how the Algolia index (left) is synced-up with the Firestore document (right)" >}}

Frontend Integrations

This lesson is integrated with multiple frontend frameworks. After deploying the backend code in this lesson, choose your favorite frontend flavor 🍧.

{{% mvp-chapter name="angular" link="/snippets/algolia-instantsearch-angular" %}} {{% mvp-chapter name="react" link="/snippets/algolia-instantsearch-react" %}} {{% mvp-chapter name="svelte" link="/snippets/algolia-instantsearch-svelte" %}}

Initial Setup

Initialize Cloud Functions

First, initialize Cloud Functions in your project with the Firebase Tools CLI. This lesson uses vanilla JS, but feel free to select TypeScript if you prefer.

{{< file "terminal" "command line" >}} {{< highlight terminal >}} npm i -g firebase-tools firebase init functions {{< /highlight >}}

Install Algolia

Indexing tasks can be handled in Node with the Algolia JS SDK package.

{{< highlight terminal >}} cd functions npm install algoliasearch {{< /highlight >}}

Create an Index

Algolia provides a guided UI for building indexes that support full-text search.

{{< figure src="img/create-index.png" caption="Create an index named customers on the Algolia dashboard" >}}

Add the Algolia API Key to Firebase

You can find your credentials under the API Keys tab. Your backend code requires the Application ID and Admin API Key. Keep the admin key safe and do not expose it to the public.

{{< figure src="img/api-keys.png" caption="You need the Algolia App ID and Admin API Key" >}}

Now set the API key and template ID in the Firebase project with the following command.

{{< file "terminal" "command line" >}} {{< highlight terminal >}} firebase functions:config:set algolia.app=YOUR_APP_ID algolia.key=ADMIN_API_KEY {{< /highlight >}}

Algolia Cloud Functions

Setup the Cloud Functions environment by initializing the Algolia client and index.

{{< file "js" "functions/index.js" >}} {{< highlight javascript >}} const functions = require('firebase-functions'); const algoliasearch = require('algoliasearch');

const APP_ID = functions.config().algolia.app; const ADMIN_KEY = functions.config().algolia.key;

const client = algoliasearch(APP_ID, ADMIN_KEY); const index = client.initIndex('customers');

/// Cloud Functions

exports.addToIndex; // TODO

exports.updateIndex; // TODO

exports.deleteFromIndex; // TODO {{< /highlight >}}

Add Record to Algolia

Our goal is to duplicate a subset of data from the Firestore customer document to Algolia. The first step is to add a new record to the index with the onCreate Firestore event.

💡 Tip. Only index data in Algolia that is actually useful for searching and/or displaying in search results. Do NOT index personally identifiable information (PII), like phone numbers and email addresses. You may not need to duplicate the entire document.

{{< highlight javascript >}} exports.addToIndex = functions.firestore.document('customers/{customerId}')

.onCreate(snapshot => {

    const data = snapshot.data();
    const objectID = snapshot.id;

    return index.addObject({ ...data, objectID });

});

{{< /highlight >}}

Update a Record in Algolia

If the Firestore document data changes, we want these changes reflected in the index and search results. We can easily handle this task with an onUpdate function.

{{< highlight javascript >}} exports.updateIndex = functions.firestore.document('customers/{customerId}')

.onUpdate((change) => {
    const newData = change.after.data();
    const objectID = change.after.id;
    return index.saveObject({ ...newData, objectID });
});

{{< /highlight >}}

Delete a Record

When a Firestore document is deleted, we must also remove it from the search index. In this case, we simply pass the objectID to Algolia within an onDelete function.

{{< highlight javascript >}} exports.deleteFromIndex = functions.firestore.document('customers/{customerId}')

.onDelete(snapshot => 
    index.deleteObject(snapshot.id)
);

{{< /highlight >}}

Deploy

Deploy your functions and test them from the Firebase console, or follow the seeding instructions in the next section.

{{< file "terminal" "command line" >}} {{< highlight terminal >}} firebase deploy --only functions {{< /highlight >}}

Optional: Seed the Database

In the video you saw how I quickly seeded Firestore with dummy data, which was accomplished with Faker and the Firebase Admin SDK. Create a vanilla node script in the functions directory that sends writes to the database.

{{< file "js" "functions/seed.js" >}} {{< highlight javascript >}} const admin = require('firebase-admin'); admin.initializeApp();

const faker = require('faker');

const db = admin.firestore();

const fakeIt = () => { return db.collection('customers').add({ username: faker.internet.userName(), avatar: faker.internet.avatar(), bio: faker.hacker.phrase() }); }

Array(20).fill(0).forEach(fakeIt); {{< /highlight >}}

Run the script from the command line like so:

{{< file "terminal" "command line" >}} {{< highlight terminal >}} cd functions node seed.js {{< /highlight >}}

{{% box icon="scroll" class="box-blue" %}} This post first appeared as Episode 109 Algolia Firestore on AngularFirebase.com and has been fully updated with the latest best practices. {{% /box %}}

You can’t perform that action at this time.