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
相关产品推荐
相关产品推荐

