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
相关产品推荐
相关产品推荐

