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

Firebase Cloud Function 编写参考及Firestore存储NaN数值问题排查

问题原因
  • 文档数据读取错误:Firestore查询返回的文档快照需要调用.data()方法才能获取字段数据,原代码直接读取.data属性(这是一个函数对象),所有取值都为undefined,参与运算后生成NaN。
  • 异步逻辑未等待:所有Firestore的get()操作都是异步任务,当前代码没有等待定价数据拉取完成就执行费用计算,cleaningPrice/discount/stay_Over/visiting这些变量在计算时还是undefined,和数字运算后直接生成NaN。
  • Booking文档查询错误:获取更新的booking文档时硬编码了.doc('{id}'),实际是在查询ID为字符串"{id}"的不存在文档,snap.data()返回空值,所有从booking取的字段都是undefined,参与运算后生成NaN。
  • 异步操作无返回值:Cloud Function要求异步场景必须返回Promise,否则函数会在IO操作完成前被强制回收,逻辑执行不完整,写入数据异常。
  • 天数计算逻辑错误:长住场景下用startDate - endDate计算天数,得到的是负数,且如果日期是Firestore Timestamp类型未转毫秒数,运算结果异常。
  • Payments查询逻辑错误:校验关联支付文档时用.doc().get()是查询随机ID的空文档,没有按booking引用过滤,遍历逻辑完全不生效,还会重复写入大量无效支付文档。
  • Booking引用对比逻辑错误:booking_ref的对比用了集合对象拼接ID,对象转字符串后格式异常,永远匹配不到已存在的支付文档。
  • 监听路径配置错误:原触发路径写为{bookings}/{id}会监听所有根集合的更新事件,实际应该固定为bookings/{id}仅监听预订集合。
修正后代码
import * as functions from 'firebase-functions';
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();

exports.paymentCalcAmount = functions.firestore
  .document(`bookings/{id}`)
  .onUpdate(async (snapshots, context) => {
    const id = context.params.id;
    let cabinetVal = 0;
    let laundry = 0;
    let fridge = 0;
    let oven = 0;
    let window = 0;
    let wall = 0;
    let cleaningPrice: number;
    let discount: number;
    let stay_Over: number;
    let visiting: number;
    let houspitality_cut: number = 0;
    let service_provider_cut: number = 0;
    let TOTALHRS: number = 0;
    let TOTALPRICE: number = 0;
    let discountedPrice: number = 0;

    // 并行拉取定价和booking数据,等待两者都返回再执行计算
    const [priceSnap, bookingSnap] = await Promise.all([
      db.collection("prices").doc("price").get(),
      db.collection('bookings').doc(id).get()
    ]);

    // 读取定价数据
    const priceData = priceSnap.data();
    cleaningPrice = priceData.cleaning;
    discount = 100 - priceData.discount;
    stay_Over = priceData.stay_over;
    visiting = priceData.visiting;

    // 读取booking数据
    const bookingData = bookingSnap.data();
    const bookingRef = `bookings/${id}`;

    if (bookingData.isCleaning === true) {
      if (bookingData.isCabinet === true) cabinetVal = 1;
      if (bookingData.isLaundry === true) laundry = 1.5;
      if (bookingData.isFridge === true) fridge = 0.5;
      if (bookingData.isOven === true) oven = 0.5;
      if (bookingData.isWindow === true) window = 1;
      if (bookingData.isWall === true) wall = 1;
      
      TOTALHRS = cabinetVal + laundry + fridge + oven + window + wall;
      TOTALPRICE = TOTALHRS * cleaningPrice;
      houspitality_cut = (TOTALPRICE / 100) * 27;
      service_provider_cut = TOTALPRICE - houspitality_cut;

      if (discount === 100) {
        discountedPrice = (TOTALPRICE / 100) * discount;
        TOTALPRICE = discountedPrice;
        houspitality_cut = (TOTALPRICE / 100) * 27;
        service_provider_cut = TOTALPRICE - houspitality_cut;
      }
    } else {
      const startDate = bookingData.startDate.toMillis();
      const endDate = bookingData.endDate.toMillis();
      if (bookingData.stayOver === true) {
        const days = Math.round(Math.abs(endDate - startDate)/(1000*60*60*24));
        TOTALPRICE = stay_Over * days;
      } else {
        const difference_in_days = Math.abs(endDate - startDate) / (1000 * 3600 * 24);
        TOTALPRICE = visiting * difference_in_days;
      }
      houspitality_cut = (TOTALPRICE / 100) * 27;
      service_provider_cut = TOTALPRICE - houspitality_cut;
    }

    // 查询关联的支付文档
    const paymentSnap = await db.collection("payments").where('booking_ref', '==', bookingRef).limit(1).get();
    const paymentData = {
      booking_ref: bookingRef,
      payment_total: TOTALPRICE,
      houspitality_cut: houspitality_cut,
      service_provider_cut: service_provider_cut,
      total_hours: TOTALHRS,
    };

    if (paymentSnap.empty) {
      // 不存在则新建
      return db.collection("payments").add(paymentData);
    } else {
      // 存在则更新
      return paymentSnap.docs[0].ref.update(paymentData);
    }
  });

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 14:48:00