Firestore中基于好友投票的菜品排名查询与数据结构设计
实现按好友投票数的菜品排名方案
数据结构调整
1. 优化现有集合结构
- Dishes集合:保留原有字段,若原
votes字段已存储所有投票用户ID则直接复用,否则新增votedUserIds数组存储该内容。 - Users集合:每个用户文档新增两个字段:
friends:数组,存储当前用户的所有好友ID(已有则无需新增)。dishFriendVoteCounts:Map类型(键为dish_id,值为数字),记录当前用户的好友对各菜品的投票总数。votedDishes:数组,存储当前用户投票过的所有菜品ID(用于好友关系变更时批量更新计数)。
2. 写操作同步逻辑
当发生投票或好友关系变更时,需同步更新计数:
- 用户投票时:
- 给目标菜品的
votes(或votedUserIds)数组添加当前用户ID。 - 将该菜品ID添加到当前用户的
votedDishes数组。 - 获取当前用户的所有好友列表,遍历每个好友的文档,将
dishFriendVoteCounts中对应菜品的计数+1(无则设为1)。
- 给目标菜品的
- 添加好友时:
- 将新好友ID添加到当前用户的
friends数组。 - 获取新好友的
votedDishes列表,遍历每个菜品ID,将当前用户的dishFriendVoteCounts中对应菜品的计数+1(无则设为1)。
- 将新好友ID添加到当前用户的
查询实现步骤
方式一:预计算计数(高性能,推荐大数据量场景)
// 1. 获取当前用户的好友投票计数 const currentUserRef = doc(db, 'users', CURRENT_USER_ID); const currentUserDoc = await getDoc(currentUserRef); const dishFriendVoteCounts = currentUserDoc.data().dishFriendVoteCounts || {}; // 2. 查询所有汤类菜品 const dishRef = collection(db, 'dishes'); const q = query(dishRef, where('categories', 'array-contains', 'Soup')); const dishesSnapshot = await getDocs(q); // 3. 匹配计数并排序 const rankedDishes = dishesSnapshot.docs.map(doc => { const dishData = doc.data(); return { ...dishData, id: doc.id, friendVoteCount: dishFriendVoteCounts[dishData.dish_id] || 0 }; }).sort((a, b) => b.friendVoteCount - a.friendVoteCount);
方式二:实时计算(适合小数据量场景,无需修改写逻辑)
如果菜品数量少、投票数不多,可直接在客户端计算好友投票数:
// 1. 获取当前用户的好友列表 const currentUserDoc = await getDoc(doc(db, 'users', CURRENT_USER_ID)); const currentUserFriends = currentUserDoc.data().friends || []; // 2. 查询所有汤类菜品 const q = query(collection(db, 'dishes'), where('categories', 'array-contains', 'Soup')); const dishesSnapshot = await getDocs(q); // 3. 计算好友投票数并排序 const rankedDishes = dishesSnapshot.docs.map(doc => { const dishData = doc.data(); const friendVoteCount = (dishData.votes || []).filter(userId => currentUserFriends.includes(userId)).length; return { ...dishData, id: doc.id, friendVoteCount }; }).sort((a, b) => b.friendVoteCount - a.friendVoteCount);
是否需要新增集合?
不需要新增集合,仅需调整现有users和dishes集合的文档结构即可。若希望投票记录更结构化,也可给每个菜品新增votes子集合(每个文档存单个投票的用户ID、时间等),但这不是必须项,视业务复杂度决定。
内容的提问来源于stack exchange,提问作者Thanh Le
相关产品推荐
相关产品推荐

