React Firestore查询嵌套集合按条件新增/更新文档异常解决
问题排查结论
你的代码存在两个核心错误,直接导致两个异常现象:
collectionGroupAPI 调用方式错误:该API仅支持传入集合名称做全局跨路径同名集合查询,不支持指定父文档路径做范围限定,你传入的参数不符合API要求,返回的查询结果不是当前用户下的评分数据,因此querySnapshot.empty判断永远不符合预期,出现重复新增的问题。- 更新操作传入了错误的引用类型:
updateDoc方法要求传入单个文档的引用作为操作对象,你传入的itemRef是整个ratedItems集合的引用,类型不匹配,因此抛出类型错误。
修正后的可运行代码
你不需要使用collectionGroup,因为你已经明确知道要查询的子集合完整父路径,直接针对当前用户名下的ratedItems子集合做查询即可:
const rateItem = async (itemId, liked) => { try { // 定位当前用户下的评分子集合 const userRatedItemsRef = collection(db, 'users', currentUser.uid, 'ratedItems'); // 在当前用户的评分集合内匹配目标itemId const q = query( userRatedItemsRef, where('itemId', '==', itemId) ); const querySnapshot = await getDocs(q); if (querySnapshot.empty) { // 无匹配条目则新增 await addDoc(userRatedItemsRef, { itemId: itemId, timestamp: serverTimestamp(), likedItem: liked, }); } else { // 取匹配到的第一条评分文档的引用执行更新 const existRatingRef = querySnapshot.docs[0].ref; await updateDoc(existRatingRef, { timestamp: serverTimestamp(), likedItem: liked, }); } } catch (err) { console.log(err.message); } };
性能优化方案
如果业务上保证同一个用户对同一个item只存在一条评分记录,你可以直接将ratedItems下的文档ID设置为itemId,完全省掉前置查询步骤,用setDoc的merge选项实现不存在则创建、存在则更新的upsert逻辑,代码更简洁、查询开销更低:
const rateItem = async (itemId, liked) => { try { // 直接用itemId作为文档ID构造引用 const ratingDocRef = doc(db, 'users', currentUser.uid, 'ratedItems', itemId); // merge: true 表示文档不存在时创建,存在时仅更新传入的字段 await setDoc(ratingDocRef, { itemId: itemId, timestamp: serverTimestamp(), likedItem: liked }, { merge: true }); } catch (err) { console.log(err.message); } };
内容的提问来源于stack exchange,提问作者Greg
相关产品推荐
相关产品推荐

