Skip to content

Instantly share code, notes, and snippets.

@bryanprimus
Created April 13, 2025 16:57
Show Gist options
  • Save bryanprimus/706d201b20d96879d359b263f5419e4f to your computer and use it in GitHub Desktop.
Save bryanprimus/706d201b20d96879d359b263f5419e4f to your computer and use it in GitHub Desktop.
Part 4: Bonus Firebase technical questions

Part 4: Firebase Technical Challenges

Question 1: Creating a Smart User Ranking System in Firestore

The traditional approach of simply chaining .orderBy() methods won't create a true multi-factor ranking system for our potential users. We need a more sophisticated solution that truly balances all three factors.

Here's my approach using a composite scoring method:

// Calculate a unified potential customer score
function calculateUserPotentialIndex(userData) {
  // Scale each metric to a comparable range
  const ratingComponent = userData.totalAverageWeightRatings / 5; // Assuming 5-star max
  
  // Apply diminishing returns for very high rental counts
  const rentalsComponent = 1 - (1 / (1 + (userData.numberOfRents / 20))); 
  
  // Convert recency to a 0-1 scale (favoring activity within last 2 weeks)
  const currentTime = Date.now() / 1000;
  const twoWeeksSeconds = 14 * 24 * 60 * 60;
  const recencyComponent = Math.max(0, Math.min(1, 1 - ((currentTime - userData.recentlyActive) / twoWeeksSeconds)));
  
  // Weight the components according to business priorities
  return (ratingComponent * 0.65) + (rentalsComponent * 0.25) + (recencyComponent * 0.10);
}

This resembles how food delivery apps rank restaurants, they don't just show the highest-rated places first. They balance rating with popularity and recency of reviews.

To implement in a real production environment:

  1. I'd create a background processor that updates this score whenever a user document changes:
updateUserPotentialScore = db
  .docs('USERS/{userId}')
  .onWrite((change, context) => {
    const user = change.after.exists ? change.after.data() : null;
    if (!user) return null;
    
    const potentialScore = calculateUserPotentialIndex(user);
    
    // Store the computed score
    return change.after.ref.update({
      potentialUserScore: potentialScore,
      // Store a timestamp so we know when this was calculated
      scoreUpdatedAt: FieldValue.serverTimestamp()
    });
  });
  1. Then for client queries, we simply use:
// First page query
const topUsersQuery = db.collection("USERS")
  .orderBy("potentialUserScore", "desc")
  .limit(20);

// For subsequent pages
function loadNextPage(lastUser) {
  return db.collection("USERS")
    .orderBy("potentialUserScore", "desc")
    .startAfter(lastUser)
    .limit(20);
}

Real-world example: This is similar to how LinkedIn ranks job candidates for recruiters. They don't just look at years of experience (our rental count), but also combine it with profile completeness (our rating) and recent activity (our recency). A holistic score helps surface the most promising candidates who might otherwise be missed by simpler filtering.

Question 2: Building a Reliable User Presence System

For tracking user online status and activity timestamps effectively, I'd implement a resilient multi-tier system:

class UserPresenceTracker {
  constructor(userId) {
    this.userId = userId;
    this.firestoreRef = db.collection("USERS").doc(userId);
    this.rtdbRef = firebase.database().ref(`/presence/${userId}`);
    this.connectionRef = firebase.database().ref('.info/connected');
    this.activityTimeout = null;
    this.inactivityThreshold = 3 * 60 * 1000; // 3 minutes
    
    this.initializePresenceMonitoring();
    this.initializeActivityTracking();
  }
  
  initializePresenceMonitoring() {
    this.connectionRef.on('value', snapshot => {
      // Connection established or re-established
      if (snapshot.val() === true) {
        // Set up what happens when client disconnects
        const offlineData = {
          status: 'offline',
          lastChanged: firebase.database.ServerValue.TIMESTAMP
        };
        
        this.rtdbRef.onDisconnect().set(offlineData).then(() => {
          // Now update current status to online
          this.rtdbRef.set({
            status: 'online',
            lastChanged: firebase.database.ServerValue.TIMESTAMP
          });
          
          // Update Firestore user document
          this.updateFirestoreActivity(true);
        });
      }
    });
    
    // Listen for RTDB status changes as a backup
    this.rtdbRef.on('value', snapshot => {
      const data = snapshot.val();
      if (data && data.status === 'offline') {
        this.updateFirestoreActivity(false);
      }
    });
  }
  
  updateFirestoreActivity(isOnline) {
    const now = Math.floor(Date.now() / 1000);
    
    this.firestoreRef.update({
      isOnline: isOnline,
      recentlyActive: now,
      // Also update timezone information for global applications
      timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
    });
  }
  
  initializeActivityTracking() {
    // Reset inactivity timer whenever user does something
    const resetTimer = () => {
      if (this.activityTimeout) {
        clearTimeout(this.activityTimeout);
      }
      
      this.activityTimeout = setTimeout(() => {
        this.updateFirestoreActivity(true);
      }, this.inactivityThreshold);
    };
    
    // Track common user interactions
    ['mousedown', 'keydown', 'touchstart', 'scroll', 'focus'].forEach(eventType => {
      window.addEventListener(eventType, resetTimer, { passive: true });
    });
    
    // Initial timer
    resetTimer();
  }
}

// Usage
const presenceTracker = new UserPresenceTracker(currentUser.uid);

I'd also implement a server-side safeguard:

checkStaleUserStatus = functions.pubsub
  .schedule('every 10 minutes')
  .onRun(async () => {
    const usersRef = admin.firestore().collection('USERS');
    
    // Define stale threshold (10 minutes ago)
    const staleThreshold = Math.floor(Date.now() / 1000) - (10 * 60);
    
    const staleUsers = await usersRef
      .where('isOnline', '==', true)
      .where('recentlyActive', '<', staleThreshold)
      .get();
    
    // Batch update stale users
    const batch = admin.firestore().batch();
    staleUsers.docs.forEach(doc => {
      batch.update(doc.ref, { 
        isOnline: false,
        // We don't update recentlyActive as that should remain when they were truly last active
      });
    });
    
    return batch.commit();
  });

Real-world example: This also shows how messaging apps like WhatsApp handle presence. They show when you're "online" but also indicate "last seen at" timestamps. The system needs to be responsive enough to show accurate status but not so aggressive that it drains mobile batteries or consumes excessive bandwidth.

For a booking app I worked on, we used a similar system to track when freelancers were actually using their reserved booking versus just having a reservation. This allowed the space to offer "hot booking" availability for walk-ins when someone with a reservation hadn't shown up within 30 minutes of their booking start time.

The multi-layered approach ensures reliability even when users lose connectivity unexpectedly or their device enters sleep mode, making the user experience smooth while maintaining accurate data for business analytics.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment