Cloud Functions & Data Modeling
Event-Triggered Functions
const { onDocumentWritten } = require('firebase-functions/v2/firestore');
exports.updateCommentCount = onDocumentWritten('posts/{postId}/comments/{commentId}', async (event) => {
// Avoid infinite loops: only update the parent if it actually needs it —
// if this write itself triggers another write to the SAME watched path,
// an unconditional update re-triggers the function forever
const before = event.data.before.exists;
const after = event.data.after.exists;
if (before === after) return; // no actual create/delete happened, skip
const delta = after && !before ? 1 : -1;
const postRef = db.doc(`posts/${event.params.postId}`);
await postRef.update({ commentCount: FieldValue.increment(delta) });
});Sharded Counters (Hot Document Fix)
// A single document has a write-rate limit — a global counter incremented
// on every user action can become a "hot document" under heavy concurrent load.
// Fix: shard the counter across multiple sub-documents, sum on read.
const NUM_SHARDS = 10;
async function incrementCounter(counterRef) {
const shardId = Math.floor(Math.random() * NUM_SHARDS);
const shardRef = counterRef.collection('shards').doc(shardId.toString());
await shardRef.update({ count: FieldValue.increment(1) });
}
async function getCount(counterRef) {
const shards = await counterRef.collection('shards').get();
return shards.docs.reduce((total, doc) => total + doc.data().count, 0);
}Denormalization
Firestore has no server-side JOIN — fetching related data across collections means multiple separate (billed) reads. Duplicating a small amount of frequently-needed data directly onto a document (e.g. storing an author's display name on each of their posts) avoids extra reads at query time, at the cost of updating that copy if the source changes. This is a deliberate, common trade-off in Firestore schema design — quite different from relational normalization instincts.
Local Emulators & Hosting
firebase init # set up hosting, functions, firestore, etc.
firebase emulators:start # local Firestore/Auth/Functions — no cloud costs
firebase deploy # ship hosting + functions + rules
firebase deploy --only firestore:rules # rules onlyKeep your own version of these notes — editable, searchable, and organised by your stack.
Start free