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

Firestore层级结构下添加用户至集合遇未处理Promise拒绝问题

Firestore「集合|文档|集合」层级添加记录触发未处理Promise拒绝问题

问题背景

采用Firestore「集合|文档|集合」层级结构,需求为:在指定文档下的集合中搜索用户ID,匹配到则更新数据,未匹配到则添加新用户记录。目前更新功能正常,但调用.set()方法添加记录时触发未处理的Promise拒绝。

现有代码片段

if (!query.empty) {
      console.log('event leaderboard exists in db');
      for (let i in leaderboard) {
        const result = leaderboard[i].data();

        for (let y in result) {
          const userLeaderboard = result[y];
          
          if (userLeaderboard.uid === currentUser.uid) {
            // 用户存在则更新分数
            return query.docs[i].ref.update({
              score: increaseBy,
            });
          } else {
            // 用户不存在则添加记录
            addUserToLeaderboard();
            
          }
        }
      }
const addUserToLeaderboard = async() => {
let userLeaderboard = {
  uid: currentUser.uid,
  score: currentTrivia.points,
  banned: false,
};

const leaderboardRef = db.collection('leaderboard').where(firebase.firestore.FieldPath.documentId(), '==', eventId);
await leaderboardRef.set(userLeaderboard, { merge: true });
}

错误原因

  1. 未处理异步函数Promise:addUserToLeaderboard是async函数,调用时未用await或.catch()捕获异常,导致未处理的Promise拒绝。
  2. 引用路径错误:db.collection('leaderboard').where(...)返回的是查询对象,而非文档引用,.set()方法仅支持文档引用,不能直接在查询对象上调用。
  3. 存在性判断逻辑缺陷:原嵌套循环会在每次遇到不匹配用户时触发添加操作,导致重复执行添加逻辑。

修复方案

1. 修正文档引用路径

将查询改为直接获取目标文档的引用:

// 原错误代码
const leaderboardRef = db.collection('leaderboard').where(firebase.firestore.FieldPath.documentId(), '==', eventId);
// 修正为直接获取文档引用
const leaderboardRef = db.collection('leaderboard').doc(eventId);

2. 正确处理异步Promise

确保外层函数为async函数,调用addUserToLeaderboard时添加await,并通过try/catch或.catch()捕获异常。

3. 优化存在性判断逻辑

先遍历所有用户确认不存在,再执行一次添加操作,避免重复触发。

修正后的完整代码

// 外层函数改为async,统一处理异步逻辑
const handleLeaderboardUpdate = async () => {
  if (!query.empty) {
    console.log('event leaderboard exists in db');
    let userExists = false;
    // 改用for...of遍历文档,避免索引遍历的潜在问题
    for (let doc of leaderboard) {
      const result = doc.data();
      for (let key in result) {
        const userLeaderboard = result[key];
        if (userLeaderboard.uid === currentUser.uid) {
          await doc.ref.update({ score: increaseBy });
          userExists = true;
          break; // 找到用户后跳出内层循环
        }
      }
      if (userExists) break; // 找到用户后跳出外层循环
    }
    // 确认用户不存在后再执行添加
    if (!userExists) {
      await addUserToLeaderboard();
    }
  } else {
    // 集合为空时直接添加用户
    await addUserToLeaderboard();
  }
};

const addUserToLeaderboard = async () => {
  const userLeaderboard = {
    uid: currentUser.uid,
    score: currentTrivia.points,
    banned: false,
  };
  // 直接定位到目标文档
  const leaderboardDocRef = db.collection('leaderboard').doc(eventId);
  await leaderboardDocRef.set(userLeaderboard, { merge: true });
};

// 调用时捕获错误,避免未处理Promise拒绝
handleLeaderboardUpdate().catch(err => {
  console.error('排行榜更新失败:', err);
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 12:45:33