You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS项目中基于Firestore的股价阈值推送及订阅方案问询

Stock Alert System with Firestore & Firebase Cloud Functions

Hey there! I’ve built a few stock alert systems with Firebase myself, so let’s walk through your questions step by step to get you unstuck.


1. Firestore Data Structure & Subscription Logic Best Practices

Your current structure (rates/stock#1 with price/name) works for storing stock data, but we need to add a dedicated structure for subscriptions to make alerting efficient. Here are two solid approaches depending on your use case:

Option 1: Subscription Records as Separate Documents (Most Flexible)

Create a top-level subscriptions collection where each document represents a single user’s subscription to a stock. This makes it easy to manage individual user subscriptions and query for all alerts tied to a specific stock.

Example structure:

/stocks/{stockId}
  - name: "Apple Inc."
  - price: 175.50
  - lastUpdated: Timestamp

/subscriptions/{subscriptionId}
  - userId: "user_123xyz"
  - stockId: "stock#1"
  - upperThreshold: 180.00  # Alert when price rises above this
  - lowerThreshold: 170.00  # Alert when price drops below this

Why this works:

  • You can quickly query all subscriptions for a stock using where("stockId", "==", targetStockId)
  • Easy to let users add/remove individual subscriptions without affecting others
  • Supports multiple thresholds per user-stock pair

Option 2: Subscribers as a Subcollection Under Stocks (Faster for Bulk Alerts)

If you need to quickly access all subscribers for a stock (e.g., high-volume alerts), nest a subscribers subcollection directly under each stock document.

Example structure:

/stocks/{stockId}
  - name: "Apple Inc."
  - price: 175.50
  - lastUpdated: Timestamp
  /subscribers/{userId}
    - upperThreshold: 180.00
    - lowerThreshold: 170.00

Why this works:

  • No cross-collection queries needed to get subscribers for a stock
  • Lower latency when triggering bulk alerts for a single stock

Key Tips:

  • Always store user IDs (not email/usernames) in subscriptions to link to user profiles
  • Add a single-field index on stockId in the subscriptions collection (Firebase will prompt you to create this if you forget)
  • For users, store their FCM push token in a users/{userId} document with a fcmToken field—this is critical for sending alerts

2. Implementing Push Alerts with Cloud Functions

We’ll use a Firestore onUpdate trigger to listen for stock price changes, check subscriptions, and send alerts via Firebase Cloud Messaging (FCM).

Step 1: Set Up the Cloud Function

First, make sure you have the Firebase CLI installed and initialized. Then create a function like this:

const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();

exports.sendStockPriceAlerts = functions.firestore
  .document("stocks/{stockId}")
  .onUpdate(async (change, context) => {
    const stockId = context.params.stockId;
    const newStockData = change.after.data();
    const oldStockData = change.before.data();
    const newPrice = newStockData.price;
    const oldPrice = oldStockData.price;
    const stockName = newStockData.name;

    // Skip if price didn't change (prevents unnecessary triggers)
    if (newPrice === oldPrice) return null;

    // Fetch all subscriptions for this stock
    const subscriptionsSnapshot = await admin.firestore()
      .collection("subscriptions")
      .where("stockId", "==", stockId)
      .get();

    // Track all push alert promises to wait for completion
    const alertPromises = [];

    subscriptionsSnapshot.forEach(async (subDoc) => {
      const subscription = subDoc.data();
      const { userId, upperThreshold, lowerThreshold } = subscription;

      // Determine if we need to send an alert
      let alertMessage = "";
      if (newPrice >= upperThreshold && oldPrice < upperThreshold) {
        alertMessage = `${stockName} hit your upper threshold! Current price: $${newPrice.toFixed(2)}`;
      } else if (newPrice <= lowerThreshold && oldPrice > lowerThreshold) {
        alertMessage = `${stockName} dropped below your lower threshold! Current price: $${newPrice.toFixed(2)}`;
      }

      if (alertMessage) {
        // Get the user's FCM token from their profile
        const userDoc = await admin.firestore().collection("users").doc(userId).get();
        if (!userDoc.exists) return;

        const fcmToken = userDoc.data().fcmToken;
        if (!fcmToken) return;

        // Build the FCM message
        const pushMessage = {
          notification: {
            title: "Stock Alert!",
            body: alertMessage,
            sound: "default"
          },
          token: fcmToken
        };

        // Add the push task to our promise array
        alertPromises.push(admin.messaging().send(pushMessage));
      }
    });

    // Wait for all alerts to send before finishing the function
    return Promise.all(alertPromises);
  });

Step 2: Critical Notes for Production

  • Error Handling: Add try/catch blocks around database queries and FCM sends to avoid function crashes
  • Bulk Sending: If you have 500+ subscribers, use admin.messaging().sendMulticast() instead of individual sends to stay within FCM limits
  • Throttling: If stock prices update frequently, add a cooldown period (e.g., 5 minutes) to avoid spamming users with repeated alerts
  • Testing: Use Firebase Emulators to test the function locally before deploying to production

内容的提问来源于stack exchange,提问作者Manuel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:13:44