Outline: [Article Title]

Keyword: [Enter Targeted Keyword]

Keyword MSV: [Enter Targeted Keyword’s Monthly Search Volume]

Author: [Enter Author Name]

Due Date: [Enter Due Date]

Publish Date: [Enter Desired Publish Date]

User Persona: [Enter Targeted Reader and/or User Persona]


Google’s Firebase is a popular app development platform used by developers all over the world. It provides you with a number of tools for developing, releasing, and monitoring your applications. Firebase, on the other hand, does not have a native indexing or search solution.For full-text search, the Firebase documentation recommends using third-party services like Algolia. Although Algolia is a good solution, it is proprietary and can be costly even at moderate scale.

Typesense has released a Firebase Extension that allows you to automatically sync Firestore documents into Typesense with just a few clicks in your Firebase project.

Firebase Extension installation guide:

This Firebase Typesense extension allows to sync data from your Firestore collection to Typesense, allowing you to perform full-text fuzzy searches on your Firestore data, including typo tolerance, faceting, filtering, sorting, curation, synonyms, geosearch, and more. This extension listens for changes to your Firestore collection and syncs new, updated, and deleted Firestore documents to Typesense. It also has a feature that allows you to backfill data.

Usage

1. Setup Prerequisites

Make sure you have the following items before installing this extension:

  1. Set up a Cloud Firestore database in your Firebase project.
  2. Setup a Typesense cluster (on Typesense Cloud or Self-Hosted).
  3. Setup a Typesense Collection either through the Typesense Cloud dashboard or through the API.

2. Install the Extension

This extension can be installed using either the Firebase Web console or the Firebase CLI.

Firebase Console

Install this extension in your Firebase project

Firebase CLI
firebase ext:install typesense/firestore-typesense-search --project=[your-project-id]

The Firebase Extensions documentation has more information on how to install extensions:

Syncing Multiple Firestore collections

You can install this extension multiple times in your Firebase project by clicking on the installation link above multiple times, and use a different Firestore collection path in each installation instance. Here is a screenshot of how this looks.

3. Backfilling data (optional)

After it is installed, this extension only syncs data that was created or changed in Firestore. To backfill data from your Firestore collection into your Typesense collection, follow these steps:

  • Create a new Firestore collection called typesense_sync through the Firestore UI.
  • Create a new document with the ID backfill and contents of {trigger: true}

This will initiate the backfill background Cloud function, which will read data from your Firestore collection and create equivalent documents in your Typesense collection.

Billing

To install an extension, your project must be on the Blaze (pay as you go) plan.

  • You will be charged a small amount (typically around $0.01/month) for the Firebase resources required by this extension (even if it is not used).
  • This extension uses other Firebase and Google Cloud Platform services, which have associated charges if you exceed the service’s free tier:
    • Cloud Firestore
    • Cloud Functions (Node.js 14+ runtime. See FAQs)
  • Usage of this extension also requires you to have a running Typesense cluster either on Typesense Cloud or some self-hosted server. You are responsible for any associated costs with these services.

Configuration Parameters

When you install this extension, you’ll be able to configure the following parameters:

Parameter Description
Firestore Collection Path The Firestore collection that needs to be indexed into Typesense.
Firestore Collection Fields A comma separated list of fields that need to be indexed from each Firestore document. Leave blank to index all fields.
Typesense Hosts A comma-separated list of Typesense Hosts. For single node clusters, a single hostname is sufficient. For multi-node Highly Available or SDN Clusters, please be sure to mention all hostnames.
Typesense API Key An Typesense API key with admin permissions. Click on “Generate API Key” in cluster dashboard in Typesense Cloud.
Typesense Collection Name Typesense collection name to index data into.
Cloud Functions location Where do you want to deploy the functions created for this extension? You usually want a location close to your database. For help selecting a location, refer to the location selection guide.

Cloud Functions

  • indexToTypesenseOnFirestoreWrite: A function that indexes data into Typesense when it’s triggered by Firestore changes.

  • backfillToTypesenseFromFirestore: A function that backfills data from a Firestore collection into Typesense, triggered when a Firestore document with the path typesense_sync/trigger has the contents of backfill: true.

Access Required

This extension will operate with the following project IAM roles:

  • datastore.user (Reason: Required to backfill data from your Firestore collection into Typesense)

Development Workflow

Run Emulator

npm run emulator
npm run typesenseServer
  • Emulator UI will be accessible at http://localhost:4000.
  • Local Typesense server will be accessible at http://localhost:8108

Add records in the Firestore UI and they should be created in Typesense.

Run Integration Tests

npm run test

Generate README

The Firebase CLI provides the following convenience command to auto-generate a README file containing content pulled from extension.yaml file and PREINSTALL.md file:

firebase ext:info ./ --markdown > README.md

Publish Extension

  • Update version number in extension.yaml
  • firebase ext:dev:publish typesense/firestore-typesense-search
    
  • Create release in Github

However, if you want to use Typesense inside Firebase without having to install any extensions, use the methods listed below.

Here is the step by step process that will show you how to integrate Typesense with Firebase to create a full-text search experience for your Firebase app in this walkthrough.Let’s assume you’re already familiar with Firebase and Firestore, as well as how they operate. Let’s start with a simple app that stores book titles and the year they were published.

// books/${bookID}
{
    id: string,
    title: string,
    publication_year: int32
}

Step 1: Run Typesense

Typesense cloud, which is the hosted version of Typesense, is the simplest way to run it:

  1. Visit https://cloud.typesense.org and Login with Github.
  2. Click on “Launch” after selecting the configuration you require or leaving the defaults config as it is.
  3. In about 5 minutes, your cluster should be fully provisioned and operational. Then select “Generate API Key” from the drop-down menu.

For the rest of the guide, we’ll use the hostname and API keys you generated earlier.

If you want to self-host Typesense, you can run it locally or on a GCP server. Here are instructions on how to install Typesense on any cloud server.

Step 2: Create a Typesense Collection

We must first create a multiple API clients in order to use Typesense. Javascript, Python, Ruby, PHP, and other API clients are supported by Typesense.

To start the Javascript client, you’ll need the Typesense server’s API key, which you got in the previous step:

import Typesense from "typesense";

let client = new Typesense.Client({
  nodes: [
    {
      host: "xxx.a1.typesense.net", // where xxx is the ClusterID of your Typesense Cloud cluster
      port: "443",
      protocol: "https",
    },
  ],
  apiKey: "<ADMIN_API_KEY>",
  connectionTimeoutSeconds: 2,
});

After that, we’ll make a collection. In relational databases, a collection is a group of related documents that can be thought of as a table. A schema is required for a collection because it represents how a document would appear.

const myCollection = {
  name: "books",
  fields: [
    { name: "id", type: "string" },
    { name: "title", type: "string" },
    { name: "publication_year", type: "int32" },
  ],
  default_sorting_field: "publication_year",
};

client.collections().create(myCollection);

The documents stored in the books collection will have three fields: id, title, and publication year. The field id is interesting because Typesense uses it as a document identifier. Typesense assigns an identifier to the document if there isn’t a id field. It’s worth noting that the id should not contain any spaces or other characters that require url encoding.

We’ll use the document’s Firestore ID as the id value in this guide.

Step 3: Write data to Typesense

After that, we’ll write functions to listen for Firestore change events and write the changes to Typesense.

New Documents

When a new document is created, we’ll write a function that adds it to Typesense’s search index also known as collection.

exports.onBookCreate = functions.firestore
  .document("/books/{bookID}")
  .onCreate((snapshot, context) => {
    // Grab the document id as id value.
    id = context.params.bookID;
    const { title, publication_year } = snapshot.data();
    document = { id, title, publication_year };

    // Index the document in books collection
    return client.collections("books").documents().create(document);
  });

Document Updates

Documents can also be updated and deleted in the same way.

exports.onBookUpdate = functions.firestore
  .document("books/{bookID}")
  .onUpdate((change, context) => {
    // Grab the changed value
    const { id, title, publication_year } = change.after.data();
    document = { id, title, publication_year };
    return client.collections("books").documents(id).update(document);
  });

Document Deletions

You only need the document’s id for delete operations:

exports.onBookDelete = functions.firestore
  .document("books/{bookID}")
  .onDelete((snap, context) => {
    // Get the document id
    id = context.params.bookID;

    return client.collections("books").documents(id).delete();
  });

You can also delete a group of documents based on a set of criteria, as explained here.

Step 4: Let the search begin!

After the data has been indexed, you can use simple search parameters to query it:

let search = {
  q: "<SEARCH_VALUE>",
  query_by: "title",
};

client
  .collections("<COLLECTION_NAME>")
  .documents()
  .search(search)
  .then(function (searchResults) {
    console.log(searchResults);
  });

Keep in mind that Typesense is a search engine that tolerates typos. So, even if you typed the search query incorrectly, you’d still get the most relevant result.

Build a Search UI

Instantsearch.js, an open-source collection of UI components created by Algolia, can now be used to add a search bar.You can use Typesense’s instantsearch adapter to create UI-based search interfaces that send queries to Typesense.

Install the Instantsearch Adapter by following these steps:

npm install typesense-instantsearch-adapter react-instantsearch-dom @babel/runtime

Next, use react-instantsearch to create a search interface:

import { InstantSearch, SearchBox, Hits, Stats } from "react-instantsearch-dom";
import TypesenseInstantSearchAdapter from "typesense-instantsearch-adapter";
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter({
  server: {
    apiKey: "xyz", // Be sure to use a Search API Key
    nodes: [
      {
        host: "xxx.a1.typesense.net", // where xxx is the ClusterID of your Typesense Cloud cluster
        port: "443",
        protocol: "https",
      },
    ],
  },
  // The following parameters are directly passed to Typesense's search API endpoint.
  //  So you can pass any parameters supported by the search endpoint below.
  //  queryBy is required.
  additionalSearchParameters: {
    queryBy: "title,description,tags",
  },
});
const searchClient = typesenseInstantsearchAdapter.searchClient;
export default function SearchInterface() {
  const Hit = ({ hit }) => (
    <p>
      {hit.title} - {hit.description}
    </p>
  );
  return (
    <InstantSearch searchClient={searchClient} indexName="pages_v1">
      <SearchBox />
      <Stats />
      <Hits hitComponent={Hit} />
    </InstantSearch>
  );
}

Instantsearch.js is a very powerful library that can be used to make some pretty cool search widgets. You can learn more about it by clicking here.

That’s all there is to it! Typesense, as we’ve seen, is simple to set up and use. It can be used to create fast, typo-tolerant search interfaces in your apps.

Closing

Typesense was built with several distinctive features primarily aimed at making the developer’s job easier while also giving customer as well as user the ability to provide a better search experience as possible.This article may have been entertaining as well as instructive in terms of how to install typesense from the ground up on a variety of platforms. Join Aviyel’s community to learn more about the open source project, get tips on how to contribute, and join active dev groups.

Call-to-Action

Aviyel is a collaborative platform that assists open source project communities in monetizing and long-term sustainability. To know more visit Aviyel.com and find great blogs and events, just like this one! Sign up now for early access, and don’t forget to follow us on our socials!