How to integrate Firebase and Typesense?
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:
- Set up a Cloud Firestore database in your Firebase project.
- Setup a Typesense cluster (on Typesense Cloud or Self-Hosted).
- 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
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 ofbackfill: 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:
- Visit https://cloud.typesense.org and Login with Github.
- Click on “Launch” after selecting the configuration you require or leaving the defaults config as it is.
- 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!