如何基于Firestore子集合内容获取用户点赞过的帖子文档?
解决方案
一、单帖查询:判断用户是否点赞并获取对应帖子
如果仅需验证单篇帖子是否被当前用户点赞,直接定位到目标upvote文档即可,验证通过后再拉取对应帖子数据:
import { doc, getDoc } from "firebase/firestore"; import { db } from "../path-to-your-firebase-config"; // 替换为你的Firebase配置路径 async function checkUserLikedPost(postId, userId) { const upvoteDocRef = doc(db, "posts", postId, "upvote", userId); const upvoteDoc = await getDoc(upvoteDocRef); if (upvoteDoc.exists()) { // 用户已点赞,获取对应帖子文档 const postDocRef = doc(db, "posts", postId); const postDoc = await getDoc(postDocRef); return postDoc.data(); } return null; // 用户未点赞 }
二、批量查询:获取用户所有点赞的帖子
Firestore不支持跨集合查询子集合的存在性,直接遍历posts下的upvote集合效率极低,建议新增反向存储结构:创建userLikes集合,结构为userLikes/[userId]/likedPosts/[postId],文档仅存exists: true。这样可以先快速获取用户点赞的所有postId,再批量拉取帖子数据。
批量查询代码(Next.js 客户端组件)
import { collection, getDocs, doc, getDoc } from "firebase/firestore"; import { db } from "../path-to-your-firebase-config"; async function getUserLikedPosts(userId) { // 第一步:获取用户点赞的所有postId const likedPostsCol = collection(db, "userLikes", userId, "likedPosts"); const likedPostsSnapshot = await getDocs(likedPostsCol); // 第二步:批量拉取对应帖子文档 const postPromises = likedPostsSnapshot.docs.map(async (docSnap) => { const postId = docSnap.id; const postDocRef = doc(db, "posts", postId); const postDoc = await getDoc(postDocRef); return postDoc.exists() ? postDoc.data() : null; }); // 过滤已删除的无效帖子 const likedPosts = (await Promise.all(postPromises)).filter(post => post !== null); return likedPosts; }
配套的点赞/取消点赞逻辑
操作点赞时需同时更新两个存储位置,保证数据一致性:
import { doc, setDoc, deleteDoc, getDoc } from "firebase/firestore"; import { db } from "../path-to-your-firebase-config"; async function togglePostLike(postId, userId) { const upvoteDocRef = doc(db, "posts", postId, "upvote", userId); const upvoteDoc = await getDoc(upvoteDocRef); if (upvoteDoc.exists()) { // 取消点赞:删除两处文档 await deleteDoc(upvoteDocRef); const userLikeDocRef = doc(db, "userLikes", userId, "likedPosts", postId); await deleteDoc(userLikeDocRef); } else { // 点赞:添加两处文档 await setDoc(upvoteDocRef, { exists: true }); const userLikeDocRef = doc(db, "userLikes", userId, "likedPosts", postId); await setDoc(userLikeDocRef, { exists: true }); } }
三、实时监听用户点赞列表(onSnapshot)
如果需要实时更新用户的点赞内容,将批量查询中的getDocs替换为onSnapshot即可:
import { collection, onSnapshot } from "firebase/firestore"; import { db } from "../path-to-your-firebase-config"; function listenToUserLikedPosts(userId, callback) { const likedPostsCol = collection(db, "userLikes", userId, "likedPosts"); return onSnapshot(likedPostsCol, async (snapshot) => { const postPromises = snapshot.docs.map(async (docSnap) => { const postId = docSnap.id; const postDocRef = doc(db, "posts", postId); const postDoc = await getDoc(postDocRef); return postDoc.exists() ? postDoc.data() : null; }); const likedPosts = (await Promise.all(postPromises)).filter(post => post !== null); callback(likedPosts); // 将最新列表传递给回调更新组件状态 }); } // 组件内使用示例 useEffect(() => { if (!currentUserId) return; const unsubscribe = listenToUserLikedPosts(currentUserId, (posts) => { setLikedPosts(posts); }); return () => unsubscribe(); // 组件卸载时取消监听 }, [currentUserId]);
内容的提问来源于stack exchange,提问作者flowoverstack
相关产品推荐
相关产品推荐

