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

