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

如何基于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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 18:20:20