Ojasa Mirai

Ojasa Mirai

Cloud

Loading...

Learning Level

🟢 Beginner🔵 Advanced
🔧 GCP Account Setup⚙️ GCP Compute Overview🚀 Cloud Run Deployment🎯 App Engine Deployment📁 GCP Storage & Hosting🔥 Firebase Hosting🗄️ Firestore Setup⚡ Firestore Realtime💾 Cloud SQL Setup📊 GCP Monitoring🔑 GCP Authentication📈 GCP Scaling & Performance⚡ Firebase Functions💰 GCP Cost Optimization
Cloud/Gcp Deployment/Firestore Realtime

⚡ Firestore Realtime

Introduction

Firestore provides real-time listeners that automatically sync data across all connected clients. Changes to documents or collections instantly propagate to every listener, enabling collaborative and live applications.

Key Learning Outcomes

By the end of this lesson, you'll understand:

  • Real-time listeners on documents and collections
  • Listening to document changes
  • Listening to collection queries
  • Unsubscribing from listeners
  • Offline persistence and synchronization
  • Real-time collaboration patterns
  • Optimizing listener performance

Document Listeners

Listen to Single Document

JavaScript:

import { doc, onSnapshot } from 'firebase/firestore';

const userRef = doc(db, 'users', 'user123');

const unsubscribe = onSnapshot(userRef, (doc) => {
  console.log('Current data:', doc.data());
});

// Stop listening
unsubscribe();

Python:

def on_snapshot(doc_snapshot, changes, read_time):
    for doc in doc_snapshot:
        print('Current data:', doc.to_dict())

db.collection('users').document('user123').on_snapshot(on_snapshot)

Listen with Error Handling

JavaScript:

const unsubscribe = onSnapshot(
  doc(db, 'users', 'user123'),
  (doc) => {
    console.log('Document:', doc.data());
  },
  (error) => {
    console.log('Error listening to document:', error);
  }
);

Collection Listeners

Listen to Query Results

JavaScript:

import { collection, query, where, onSnapshot } from 'firebase/firestore';

const q = query(
  collection(db, 'posts'),
  where('author', '==', 'user123')
);

const unsubscribe = onSnapshot(q, (snapshot) => {
  const posts = [];
  snapshot.forEach((doc) => {
    posts.push({
      id: doc.id,
      ...doc.data()
    });
  });
  console.log('Current posts:', posts);
});

Python:

def on_snapshot(docs, changes, read_time):
    posts = []
    for doc in docs:
        posts.append({'id': doc.id, **doc.to_dict()})
    print('Current posts:', posts)

db.collection('posts').where('author', '==', 'user123').on_snapshot(on_snapshot)

Listen to Changes

JavaScript:

const unsubscribe = onSnapshot(
  collection(db, 'users'),
  (snapshot) => {
    snapshot.docChanges().forEach((change) => {
      if (change.type === 'added') {
        console.log('New user:', change.doc.data());
      }
      if (change.type === 'modified') {
        console.log('Modified user:', change.doc.data());
      }
      if (change.type === 'removed') {
        console.log('Removed user ID:', change.doc.id);
      }
    });
  }
);

Real-Time Chat Example

JavaScript:

import { collection, query, orderBy, onSnapshot, addDoc, serverTimestamp } from 'firebase/firestore';

// Listen to messages
const chatRef = collection(db, 'chats', 'room1', 'messages');
const q = query(chatRef, orderBy('timestamp', 'asc'));

const unsubscribe = onSnapshot(q, (snapshot) => {
  const messages = [];
  snapshot.forEach((doc) => {
    messages.push({
      id: doc.id,
      ...doc.data()
    });
  });
  
  // Update UI with messages
  displayMessages(messages);
});

// Send message
async function sendMessage(text) {
  await addDoc(chatRef, {
    text: text,
    author: currentUser.id,
    timestamp: serverTimestamp()
  });
}

Offline Persistence

JavaScript (automatically enabled for web):

import { enableIndexedDbPersistence } from 'firebase/firestore';

try {
  await enableIndexedDbPersistence(db);
  console.log('Offline persistence enabled');
} catch (err) {
  if (err.code == 'failed-precondition') {
    console.log('Multiple tabs open, persistence disabled');
  } else if (err.code == 'unimplemented') {
    console.log('Browser does not support persistence');
  }
}

Unsubscribing from Listeners

JavaScript:

import { onSnapshot } from 'firebase/firestore';

// Store unsubscribe function
const listeners = [];

function startListening() {
  const unsubscribe = onSnapshot(
    doc(db, 'users', 'user123'),
    (doc) => {
      console.log('Updated:', doc.data());
    }
  );
  listeners.push(unsubscribe);
}

function stopAllListeners() {
  listeners.forEach(unsubscribe => unsubscribe());
  listeners = [];
}

// In React cleanup
useEffect(() => {
  const unsubscribe = onSnapshot(
    collection(db, 'users'),
    (snapshot) => {
      // Update state
    }
  );

  return () => unsubscribe();
}, []);

Real-Time Collaboration Example

JavaScript (Multi-user document):

import { doc, onSnapshot, updateDoc } from 'firebase/firestore';

const docRef = doc(db, 'documents', 'shared-doc');

// Listen to document changes
onSnapshot(docRef, (doc) => {
  updateUIWithContent(doc.data().content);
});

// User edits content
async function updateContent(newContent) {
  await updateDoc(docRef, {
    content: newContent,
    lastEdited: new Date(),
    editedBy: currentUserId
  });
}

Optimizing Listeners

1. Limit Query Scope

Good:

// Only listen to recent messages
const q = query(
  collection(db, 'messages'),
  orderBy('timestamp', 'desc'),
  limit(100)
);

2. Unsubscribe When Not Needed

Good:

useEffect(() => {
  const unsubscribe = onSnapshot(...);
  return () => unsubscribe();
}, []);

3. Filter on Client Side When Appropriate

onSnapshot(collection(db, 'users'), (snapshot) => {
  const activeUsers = snapshot.docs
    .map(doc => doc.data())
    .filter(user => user.isActive);
});

Best Practices

  • **Unsubscribe in cleanup** to prevent memory leaks
  • **Limit query results** to avoid syncing unnecessary data
  • **Use specific queries** instead of listening to entire collections
  • **Leverage offline persistence** for better UX
  • **Handle errors** from listeners appropriately

Key Takeaways

  • **Real-time listeners** automatically sync document changes
  • **onSnapshot** works on documents and queries
  • **docChanges()** shows added, modified, and removed documents
  • **Offline persistence** keeps data available without connection
  • **Unsubscribe** to prevent memory leaks and save bandwidth
  • **Collaborative apps** are enabled by real-time synchronization

Next Steps

Explore Cloud Functions for server-side logic triggered by Firestore changes, or learn about authentication to secure real-time data.


Resources

Python Docs

Ojasa Mirai

Master AI-powered development skills through structured learning, real projects, and verified credentials. Whether you're upskilling your team or launching your career, we deliver the skills companies actually need.

Learn Deep • Build Real • Verify Skills • Launch Forward

Courses

PythonFastapiReactJSCloud

© 2026 Ojasa Mirai. All rights reserved.

TwitterGitHubLinkedIn