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

Firebase Database Web问题:如何仅展示用户已购买的视频列表

解决Firebase Database只展示用户已购视频的问题

作为有SQL背景刚转Firebase的开发者,你肯定会觉得这种“只展示用户有权限内容”的逻辑和传统SQL思路不太一样——毕竟Firebase是NoSQL,核心是数据结构设计+安全规则+精准查询,而不是先拉全部再过滤(而且前端过滤还不安全)。下面一步步帮你搞定:

第一步:先理清楚合理的数据结构

Firebase的结构直接决定了后续查询的效率和安全性,推荐两种常用结构:

结构1:用户购买记录存为数组(适合少量购买的场景)

  • videos 集合:每个文档对应一个视频,字段比如 id(文档ID)、title、description、price 等
  • userPurchases 集合:文档ID用用户的UID,里面存一个数组字段 purchasedVideoIds,比如 ["video_123", "video_456"]

结构2:用户购买记录存为子集合(适合大量购买的场景)

  • videos 集合同上
  • userPurchases/{userId}/purchases 子集合:每个文档的ID是视频ID,字段可以加购买时间 purchaseTime 等,这样扩展性更强

第二步:配置安全规则(必须!不能只靠前端过滤)

安全规则是Firebase的第一道防线,确保用户无论如何都无法读取未购买的视频。这里以结构2为例写规则:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // 用户只能读写自己的购买记录
    match /userPurchases/{userId}/purchases/{videoId} {
      allow read, write: if request.auth != null && request.auth.uid == userId;
    }
    
    // 用户只能读取自己购买过的视频
    match /videos/{videoId} {
      allow read: if request.auth != null && exists(/databases/$(database)/documents/userPurchases/$(request.auth.uid)/purchases/$(videoId));
      // 如果用结构1(数组),规则改成:
      // allow read: if request.auth != null && videoId in get(/databases/$(database)/documents/userPurchases/$(request.auth.uid)).data.purchasedVideoIds;
    }
  }
}

第三步:前端实现精准查询

现在安全规则已经限制了访问权限,前端只需要查询用户已购买的视频即可。这里用JavaScript SDK举例子:

先获取用户的购买视频ID列表

import { getAuth, onAuthStateChanged } from "firebase/auth";
import { getFirestore, doc, getDoc, collection, where, getDocs } from "firebase/firestore";

const auth = getAuth();
const db = getFirestore();

// 监听用户登录状态(必须确保用户已登录)
onAuthStateChanged(auth, async (user) => {
  if (user) {
    const userId = user.uid;
    
    // 方式1:如果用结构2(子集合)
    const purchasesCol = collection(db, `userPurchases/${userId}/purchases`);
    const purchasesSnapshot = await getDocs(purchasesCol);
    const purchasedVideoIds = purchasesSnapshot.docs.map(doc => doc.id);
    
    // 方式2:如果用结构1(数组)
    // const userPurchaseDoc = await getDoc(doc(db, "userPurchases", userId));
    // const purchasedVideoIds = userPurchaseDoc.data()?.purchasedVideoIds || [];
    
    // 然后查询这些视频的详情
    if (purchasedVideoIds.length > 0) {
      // 注意:Firestore的where-in查询最多支持30个ID,如果超过需要分批查询
      const videosQuery = collection(db, "videos").where(
        firebase.firestore.FieldPath.documentId(), 
        "in", 
        purchasedVideoIds
      );
      const videosSnapshot = await getDocs(videosQuery);
      
      // 渲染已购视频到页面
      videosSnapshot.docs.forEach(doc => {
        const video = doc.data();
        console.log(video.title);
        // 这里写你的DOM渲染逻辑,比如创建视频卡片
      });
    } else {
      // 用户还没有购买任何视频,显示提示
      console.log("您还没有购买任何视频");
    }
  } else {
    // 用户未登录,跳转到登录页面
    console.log("请先登录");
  }
});

关键思路对比(SQL vs Firebase)

你之前习惯的SQL思路是:SELECT * FROM videos WHERE id IN (SELECT video_id FROM user_purchases WHERE user_id = 'xxx'),Firebase的思路其实类似,但需要注意:

  • Firebase不能直接做嵌套查询,所以需要先获取购买的ID列表,再查视频
  • 必须依赖安全规则,而不是只靠前端过滤(前端过滤很容易被绕过)

这样设置后,用户不仅在页面上只能看到已购视频,即使通过API直接请求未购视频,也会被安全规则拦截,完全符合你的需求。


内容的提问来源于stack exchange,提问作者Anson Bolinger

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 08:57:42