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

使用Firebase getDocs获取子集合时遇TypeError: cannot add a new property错误

问题分析与解决方案

错误原因

  1. 未处理的Promise拒绝:你在savingsSnapshot.forEach中使用了async回调函数,但forEach不会等待异步操作完成,导致这些异步任务的Promise没有被正确捕获,触发了Possible Unhandled Promise Rejection警告。
  2. 变量名冲突+不可扩展对象:内部contributionsSnapshot.forEach的参数名和外部的doc重名,同时Firestore返回的doc.data()对象是不可扩展/冻结的,若误操作原对象(比如试图直接添加属性),就会抛出TypeError: cannot add a new property。

修复后的代码

let savings = [];
const savingsRef = collection(userRef, "savings");
const savingsSnapshot = await getDocs(savingsRef);

// 用for...of替代forEach,支持await异步操作
for (const doc of savingsSnapshot.docs) {
    let contributions = [];
    let currentSum = 0;
    const contributionsRef = collection(doc.ref, "contributions");
    const contributionsSnapshot = await getDocs(contributionsRef);
    
    // 内部循环改用不同参数名,避免变量冲突
    contributionsSnapshot.forEach((contribDoc) => {
        const data = contribDoc.data();
        console.log(data);
        // 新建对象存储数据,避免操作Firestore返回的不可扩展对象
        contributions.push({ 
            ref: contribDoc.ref, 
            ...data 
        });
        currentSum += Number(data.amount);
    });
    
    // 同样新建对象存储saving数据,同时可加入计算好的总额
    savings.push({
        ref: doc.ref,
        ...doc.data(),
        currentSum: currentSum
    });
}

关键改动说明

  • 替换forEach为for...of:for...of支持在循环中使用await,确保每个异步操作完成后再执行下一次循环,彻底解决未处理Promise的问题。
  • 重命名内部循环参数:将内部文档变量改为contribDoc,避免和外部的saving文档变量doc混淆,消除潜在的误操作风险。
  • 显式提取数据对象:虽然展开运算符本身不会修改原对象,但显式提取data变量更清晰,也能彻底避免触碰Firestore返回的不可扩展对象。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 02:05:11