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

Cloud Firestore根据手机号获取AuthId及路径错误排查求助

解决Cloud Firestore中"documentPath is not a valid ResourcePath"错误及转账逻辑修复

看起来你在实现Firestore转账功能时遇到了路径无效的错误,核心问题在于异步操作处理不当导致payeeDocId未被正确赋值,同时还有一些字段获取和事务使用的问题,下面一步步帮你梳理修复:

1. 核心错误原因:异步查询未正确等待

你的代码中,payeeQuery.get()是异步Promise操作,后面直接使用payeeDocId的时候,Promise还没完成,payeeDocId还是undefined,这就导致db1.collection('deyaPayusers').doc(payeeDocId)的路径无效(空文档ID不符合要求)。

2. 其他关键问题

  • 错误获取文档字段:你直接通过usersRef.PhoneNo、walletRefPayer.Usd获取字段是错误的,这些是DocumentReference对象,不是文档数据,必须先调用get()获取快照再从data()中提取。
  • 事务方法拼写错误:Firestore的事务方法是runTransaction(单数),不是runTransactions。
  • 事务逻辑拆分风险:转账是原子操作,扣款和加款必须放在同一个事务里,分开两个事务会导致数据不一致(比如扣款成功但加款失败)。

修复后的完整代码

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(); // 必须初始化Admin SDK

exports.transactionDetails = functions.firestore
  .document('deyaPayusers/{authid}/Transaction/{transid}') // 将authid1改为transid,语义更清晰
  .onWrite(async (change, context) => { // 使用async/await简化异步逻辑
    const db = admin.firestore();
    const payerAuthId = context.params.authid;
    const transId = context.params.transid;
    
    // 处理删除交易的情况
    const newValue = change.after.data();
    if (!newValue) return null;

    const payeePhone = newValue.Payee;
    const transferAmount = newValue.Amount;

    // 1. 获取付款人钱包余额
    const payerWalletRef = db.collection('deyaPayusers').doc(payerAuthId).collection('Wallet').doc(payerAuthId);
    const payerWalletSnap = await payerWalletRef.get();
    
    if (!payerWalletSnap.exists) {
      console.error('付款人钱包不存在');
      await change.after.ref.update({ Status: 'FAILURE', Reason: 'Payer wallet not found' });
      return null;
    }
    const currentPayerBalance = payerWalletSnap.data().Usd || 0;

    // 检查余额是否足够
    if (currentPayerBalance < transferAmount) {
      console.error('付款人余额不足');
      await change.after.ref.update({ Status: 'FAILURE', Reason: 'Insufficient balance' });
      return null;
    }

    // 2. 通过手机号查询收款人AuthId
    const payeeQuerySnap = await db.collection('deyaPayusers').where('PhoneNo', '==', payeePhone).get();
    
    if (payeeQuerySnap.empty) {
      console.error('收款人不存在');
      await change.after.ref.update({ Status: 'FAILURE', Reason: 'Payee not found' });
      // 这里可以添加邀请收款人的逻辑
      return null;
    }
    // 假设一个手机号对应唯一用户,取第一个文档ID
    const payeeAuthId = payeeQuerySnap.docs[0].id;

    // 3. 检查收款人钱包是否存在
    const payeeWalletRef = db.collection('deyaPayusers').doc(payeeAuthId).collection('Wallet').doc(payeeAuthId);
    const payeeWalletSnap = await payeeWalletRef.get();
    
    if (!payeeWalletSnap.exists) {
      console.error('收款人钱包不存在');
      await change.after.ref.update({ Status: 'FAILURE', Reason: 'Payee wallet not found' });
      return null;
    }

    // 4. 执行原子转账事务
    try {
      await db.runTransaction(async (transaction) => {
        // 事务中重新获取最新钱包数据,避免并发冲突
        const payerWalletDoc = await transaction.get(payerWalletRef);
        const payeeWalletDoc = await transaction.get(payeeWalletRef);

        const newPayerBalance = payerWalletDoc.data().Usd - transferAmount;
        const newPayeeBalance = payeeWalletDoc.data().Usd + transferAmount;

        // 同时更新双方钱包
        transaction.update(payerWalletRef, { Usd: newPayerBalance });
        transaction.update(payeeWalletRef, { Usd: newPayeeBalance });
      });

      // 事务成功,更新交易状态
      await change.after.ref.update({ Status: 'SUCCESS', PayeeAuthId: payeeAuthId });
      console.log('转账完成');
    } catch (error) {
      console.error('事务执行失败', error);
      await change.after.ref.update({ Status: 'FAILURE', Reason: 'Transaction failed' });
    }

    return null;
  });

额外优化说明

  • 适配了Firebase Functions v1.0+的参数规范,将旧的event改为change和context(旧参数已废弃)。
  • 添加了交易状态更新,方便后续追踪交易结果。
  • 补充了各种异常场景的处理(钱包不存在、收款人不存在等),避免函数崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:56:30