Firebase
02 / 02

Cloud Functions & Data Modeling

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 only

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free