1

To support case-insensitive or any other canonicalization do we need to write a separate field that contains the canonicalized version and query against that??. For example:

db.collection("users").where("name", "==", "Dan")

db.collection("users").where("name_lowercase", "==", "dan")
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807

2 Answers2

2

What I would do:

  1. Before querying (maybe client-side): convert the query term in two or more variations (10 variations is maximum). For example, the search term "dan" (String) becomes an array of ["dan", "DAN", "Dan"]

  2. Then I would do a "in" query, where I would search all of those variations in the same name field.

The "in" query type supports up to 10 equality (==) clauses with a logical "OR" operator. (documentation here)

This way, you can keep only one field "name" and query with possible variations on it.

It would look like this:

let query_variations = ["dan", "DAN", "Dan"]; // TODO: write a function that converts the query string into this kind of Array
let search = await db.collection("users").where("name", "in", query_variations).get();
2

In short, yes.

This is because Cloud Firestore (and the Firebase Realtime Database, when enabled) are indexed databases based on the values of each property in a document.

Rather than search through hundreds (if not thousands and thousands) of documents for matches, the index of the relevant property is queried for matching document IDs.

Consider the following "database" and it's index based on the name in the documents:

const documents = {
  "docId1": {
    name: "dan"
  },
  "docId2": {
    name: "dan"
  },
  "docId3": {
    name: "Dan"
  },
  "docId4": {
    name: "Dan"
  }
}

const nameIndex = {
  "dan": ["docId1, docId2"],
  "Dan": ["docId3, docId4"]
}

Instead of calling Object.entries(documents).filter(([id, data]) => data.name === "dan") on the entire list of documents, you can just ask the index instead using nameIndex["dan"] yielding the final results ["docId1, docId2"] near-instantly ready to be retrieved.

Continuing that same example, calling nameIndex["daniel"] gives undefined (no documents with that name) which can quickly be used to say that the data doesn't exist in the database).

Firestore introduced composite indexes, which allows you to index across multiple properties such as "name" and "age" so you can also quickly and efficiently search documents where the name is "Dan" but they are also 42 years of age.

Further reading: The Firebase documentation covers one solution for text-based search here.

samthecodingman
  • 23,122
  • 4
  • 30
  • 54