Angular+Firestore中Map类型角色的可访问文档查询问题
问题:如何查询Firestore中当前用户可访问的寺庙文档?
背景信息
集合数据结构
Firestore的temples集合中文档结构如下:
{ name: 'Sri Chamundeshwari temple', address: 'Chamundi hills, Mysore', roles: { 'owner@gmail.com': 'owner', 'admin@gmail.com': 'admin', 'member@gmail.com': 'member', 'viewer@gmail.com': 'viewer' } }
安全规则
已设置如下安全规则,仅允许roles对象中存在的用户访问对应文档:
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /temples/{temple} { function isSignedIn() { return request.auth != null; } function getRole(rsc) { return rsc.data.roles[request.auth.token.email]; } function isOneOfRoles(rsc, array) { return isSignedIn() && getRole(rsc) in array; } allow read: if isOneOfRoles(resource, ['owner', 'admin', 'member', 'viewer']); } } }
问题描述
需要编写查询语句,获取当前登录用户可访问的所有寺庙文档(例如用户在3个文档中拥有viewer角色,预期返回这3个文档),但尝试的查询均返回权限错误:
ERROR FirebaseError: Missing or insufficient permissions.
尝试过的查询
// 尝试1:集合组查询 const q = query( collectionGroup(this.fireStore, "temples"), where(`roles.${this.auth.currentUser?.email}`, 'array-contains', ['owner', 'administrator', 'member', 'viewer']) );
// 尝试2:普通集合查询 const q = query( collection(this.fireStore, "temples"), where(`roles.${this.auth.currentUser?.email}`, 'array-contains', ['owner', 'administrator', 'member', 'viewer']) );
更新:将array-contains替换为in操作符后,仍出现权限错误。
解决方案
1. 修正查询语句
你的数据结构中,roles是对象而非数组,每个用户邮箱对应一个字符串类型的角色值,因此需要使用in操作符直接匹配角色值,同时确保查询条件与安全规则的逻辑严格一致:
const userEmail = this.auth.currentUser?.email; if (!userEmail) { // 处理用户未登录的边界情况 return; } const q = query( collection(this.fireStore, "temples"), where(`roles.${userEmail}`, 'in', ['owner', 'admin', 'member', 'viewer']) );
2. 关键注意事项
- 数据类型匹配:
roles.{userEmail}是字符串类型(如'viewer'),而非数组,因此不能使用array-contains(该操作符仅用于匹配数组中的元素)。 - 规则与查询的兼容性:Firestore要求查询条件必须能让服务器提前筛选出符合安全规则的文档。你的安全规则检查用户邮箱对应的角色是否在指定数组中,查询使用
in操作符匹配相同的角色数组,两者逻辑对齐后才能通过权限验证。 - 避免空值问题:必须确保
currentUser?.email不为空,否则会生成无效的查询路径(如roles.undefined),直接导致权限错误或查询失败。
3. 额外优化建议
如果后续角色类型可能扩展,建议将角色列表抽成常量,避免重复编写:
const ALLOWED_ROLES = ['owner', 'admin', 'member', 'viewer']; // 安全规则中同步使用该常量(需在规则内定义对应常量) // 查询中直接调用 where(`roles.${userEmail}`, 'in', ALLOWED_ROLES)
内容的提问来源于stack exchange,提问作者Karthik Nagaraj
相关产品推荐
相关产品推荐

