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

基于TypeScript的Cloud Function多数据库读取开发求助

TypeScript Cloud Function: Fetch Bookings, Get Customer Tokens & Send Notifications

Hey there! I get it—when juggling multiple database nodes and async operations, code can quickly turn into a mess. Let's build this out step by step with clean, structured TypeScript code that makes sense.

First, let’s assume we’re working with Firebase Realtime Database (adjustments for Firestore are straightforward if needed) and Firebase Cloud Messaging (FCM) for sending notifications. Here’s a clear breakdown of the solution:

1. Set Up the Cloud Function Trigger

We’ll use an onWrite trigger to listen for changes in the bookings node. This fires whenever a booking is created, updated, or deleted.

2. Extract the Customer Value from the Booking

When the trigger activates, we’ll grab the latest booking data and pull out the customer field we need.

3. Fetch Corresponding Tokens from Notifications

Using the customer identifier, we’ll query the notifications node to get all FCM tokens linked to that customer.

4. Send Notifications to the Tokens

Finally, we’ll loop through the valid tokens and send a notification using FCM, plus clean up any invalid tokens afterward.

Full TypeScript Code Example

import * as functions from "firebase-functions";
import * as admin from "firebase-admin";

// Initialize Firebase Admin (only needs to run once)
admin.initializeApp();

// Reference to Realtime Database
const db = admin.database();

// Cloud Function to handle booking changes and trigger notifications
export const onBookingChange = functions.database.ref("/bookings/{bookingId}")
  .onWrite(async (change, context) => {
    try {
      // Skip logic if the booking is being deleted
      const newBooking = change.after.val();
      if (!newBooking) {
        functions.logger.info("Booking deleted, skipping notification workflow");
        return null;
      }

      // Extract the customer value from the booking data
      const customer = newBooking.customer;
      if (!customer) {
        functions.logger.error("No customer field found in the booking");
        return null;
      }

      // Fetch all FCM tokens associated with this customer
      const tokensSnapshot = await db.ref(`/notifications/${customer}/tokens`).once("value");
      const tokens = tokensSnapshot.val();

      if (!tokens) {
        functions.logger.info(`No notification tokens found for customer: ${customer}`);
        return null;
      }

      // Convert token object to an array (assuming tokens are stored as { token1: true, token2: true })
      const tokenArray = Object.keys(tokens);

      // Customize this payload to match your app's notification needs
      const notificationPayload = {
        notification: {
          title: "Booking Update",
          body: `Your booking (ID: ${context.params.bookingId}) has been updated!`,
        },
        data: {
          bookingId: context.params.bookingId,
          customerId: customer,
          // Add any other custom data your app needs here
        },
      };

      // Send notifications to all valid tokens
      const fcmResponse = await admin.messaging().sendToDevice(tokenArray, notificationPayload);

      // Clean up invalid/unregistered tokens from the database
      const failedTokens: string[] = [];
      fcmResponse.results.forEach((result, index) => {
        const error = result.error;
        if (error) {
          functions.logger.error(`Failed to send to token ${tokenArray[index]}:`, error);
          // Mark tokens that are no longer valid for removal
          if (error.code === "messaging/invalid-registration-token" ||
              error.code === "messaging/registration-token-not-registered") {
            failedTokens.push(tokenArray[index]);
          }
        }
      });

      if (failedTokens.length > 0) {
        const updates: { [key: string]: null } = {};
        failedTokens.forEach(token => {
          updates[`/notifications/${customer}/tokens/${token}`] = null;
        });
        await db.ref().update(updates);
        functions.logger.info(`Removed ${failedTokens.length} invalid tokens from database`);
      }

      functions.logger.info(`Successfully sent notifications to ${tokenArray.length - failedTokens.length} devices`);
      return null;

    } catch (error) {
      functions.logger.error("Error processing booking change:", error);
      return null;
    }
  });

Key Customization Tips:

  • Database Structure: This code assumes your notifications node is structured like /notifications/{customerId}/tokens/{tokenId}: true. Adjust the path if your tokens are stored differently (e.g., as an array).
  • Notification Payload: Tweak the title, body, and data fields to fit your app’s user experience.
  • Firestore Adaptation: If using Firestore instead of Realtime Database, replace admin.database() calls with admin.firestore() and adjust queries (e.g., db.collection("notifications").doc(customer).collection("tokens").get()).
  • Error Handling: Expand the try/catch block to handle edge cases like missing permissions or network timeouts if needed.

This modular structure keeps each step clear and avoids callback hell, making it easier to debug and maintain as your function evolves.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 04:00:07