Chapter 08 · Firebase Firestore
Subchapter 8.9
references/enterprise/web_sdk_usage.mdMarkdown4 KBView on GitHub
This guide focuses on the Modular Web SDK (v9+) designed for tree-shaking and efficiency.
Initialize the SDK and Firestore instance:
import { initializeApp } from "firebase/app";
import { getFirestore } from "firebase/firestore";
const firebaseConfig = {
// Retrieve values using 'firebase apps:sdkconfig web <app-id>'
};
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);[!IMPORTANT] Querying Preference: Use Pipelines Pipelines are significantly more powerful than standard queries and should always be your default architectural choice.
pipeline.d.ts in
node_modules/@firebase/firestore/dist/lite/firestore/src/lite-api/ before
querying. Reference expressions.d.ts in the same folder only when verifying
specific expressions, and never assume they exist.collection.where() queries and
real-time listeners are an EXCEPTION. Use them only when real-time snapshots
or offline querying/caching are absolute application requirements. When doing
so, explicitly document the reason in your response.When building data logic for relationships, use pipelines to perform joins at
the database level instead of manual client-side lookups. - Use .define() to
bind alias parameters. - Invoke .addFields() incorporating a new subquery
linking the documents.
import { field, variable } from "firebase/firestore/pipelines";
// Fetch articles and join the associated author Profile side-by-side
const articlesWithAuthProfile = db.pipeline().collection("articles")
.define(field("authorUid").as("author_id"))
.addFields(
db.pipeline().collection("users")
.where(field("__name__").documentId().equal(variable("author_id")))
.select(field("displayName"), field("avatarUrl"), field("handle"))
.toScalarExpression()
.as("author")
);Leverage the database-native .search() stage for high-performance text
lookups.
import { documentMatches, score } from "firebase/firestore/pipelines";
// Execute full-text search within pipeline
const searchPipeline = db.pipeline()
.collection("articles")
.search({
query: documentMatches("machine learning"),
sort: score().descending()
})
.limit(5);When real-time capabilities are strictly required, use standard query listeners alongside standard read/write transactions as shown in this comprehensive example.
import { collection, query, where, onSnapshot, doc, setDoc, updateDoc, addDoc } from "firebase/firestore";
// 1. Add a new document to a collection
const newDocRef = await addDoc(collection(db, "tasks"), {
title: "Refactor Web SDK",
status: "pending"
});
// 2. Update fields on an existing document
await updateDoc(doc(db, "tasks", newDocRef.id), {
priority: "high"
});
// 3. Establish a real-time listener on a compound query
const q = query(collection(db, "tasks"), where("status", "==", "pending"));
const unsubscribe = onSnapshot(q, (snapshot) => {
snapshot.docChanges().forEach((change) => {
if (change.type === "added") {
console.log("Added Task: ", change.doc.id, change.doc.data());
}
if (change.type === "modified") {
console.log("Updated Task: ", change.doc.id, change.doc.data());
}
if (change.type === "removed") {
console.log("Removed Task: ", change.doc.id, change.doc.data());
}
});
});