Firestore:如何查询文档子集合中的角色映射?
Firestore: How to query a map of roles inside a subcollection of documents?
我有以下子集合结构:
/projects/{projectId}/documents/{documentId}
其中每个文档都有一个 access
映射用于检查每个文档的安全规则:
{
title: "A Great Story",
content: "Once upon a time ...",
access: {
alice: true,
bob: false,
david: true,
jane: false
// ...
}
}
如何设置安全规则:
match /{path=**}/documents/{documentId} {
allow list, get: if resource.data.access[request.auth.uid] == true;
}
当我想查询 alice 可以跨所有项目访问的所有文档时:
db.collectionGroup("documents").where(`access.${uid}`, "==", true);
我收到一条错误消息,提示我需要为 access.alice
、access.david
等创建集合组索引
如何解决集合组查询的索引编制问题?
如 https://cloud.google.com/firestore/docs/query-data/queries#collection-group-query 所述,“在使用集合组查询之前,您必须创建一个支持您的集合组查询的索引。您可以通过错误消息、控制台或 Firebase CLI 创建索引."
在这种情况下,您需要在访问映射 (https://cloud.google.com/firestore/docs/query-data/indexing#add_a_single-field_index_exemption)
上启用 CollectionGroup 查询
如@Jim 所述,您必须为其创建索引。
如果你不想深入了解它,你可以直接捕获错误,它会直接 link 来创建一个,如下所示:
db.collectionGroup("documents").where(`access.${uid}`, "==", true).get().then((snap) => {
//
}).catch((e) => console.log(e))
文档中提到的其他方式包括:
Before using a collection group query, you must create an index that
supports your collection group query. You can create an index through
an error message, the console, or the Firebase CLI.
作为索引的快速概述,有两种类型 - 复合索引(用于将多个字段连接在一起)或单字段索引。默认情况下,对于普通集合查询,单字段索引会自动为文档的每个字段创建,而对于集合组查询则禁用。如果字段的值是数组,则该数组的值将添加到 Array Contains 索引中。如果字段的值是原始值(字符串、数字、时间戳等),文档将添加到该字段的 Ascending 和 Descending 索引.
要为集合组查询启用 access
字段查询,您必须创建索引。虽然您可以在进行查询时收到的错误消息中单击 link,但这只会为您正在查询的用户添加索引(例如 access.alice
、access.bob
,等等).相反,您应该使用 Firebase Console 告诉 Cloud Firestore 为 access
创建索引(这将为其每个子项创建索引)。打开控制台后,使用“添加豁免”按钮(将“豁免”的这种用法视为“覆盖默认设置”)定义新的索引规则:
在第一个对话框中,使用这些设置:
Collection ID: "documents"
Field Path: "access"
Collection: Checked ✔
Collection group: Checked ✔
在第二个对话框中,使用这些设置:
Collection Scope
Collection Group Scope
Ascending
Enabled
Enabled
Descending
Enabled
Enabled
Array Contains
Enabled
Enabled
在你的安全规则中,你还应该在做相等之前检查目标用户是否在access
映射中。访问丢失的 属性 时会抛出“属性 在对象上未定义。”拒绝访问的错误,如果您稍后将语句与 ||
.
组合在一起,这将成为一个问题
要解决此问题,您可以使用:
match /{path=**}/documents/{documentId} {
allow list, get: if request.auth.uid in resource.data.access
&& resource.data.access[request.auth.uid] == true;
}
或在找不到所需键时提供后备值:
match /{path=**}/documents/{documentId} {
allow list, get: if resource.data.access.get(request.auth.uid, false) == true;
}
作为违反规则的示例,假设您希望“职员”用户能够阅读文档,即使他们不在该文档的 access
映射中。
这些规则总是会出错并失败(如果工作人员的用户 ID 不在 access
映射中):
match /{path=**}/documents/{documentId} {
allow list, get: if resource.data.access[request.auth.uid] == true
|| get(/databases/$(database)/documents/users/$(request.auth.uid)).data.get("staff", false) == true;
}
然而,这些规则将起作用:
match /{path=**}/documents/{documentId} {
allow list, get: if resource.data.access.get(request.auth.uid, false) == true
|| get(/databases/$(database)/documents/users/$(request.auth.uid)).data.get("staff", false) == true;
}
附带说明一下,除非您需要查询用户无权访问的文档,否则从访问映射中省略该用户会更简单。
{
title: "A Great Story",
content: "Once upon a time ...",
access: {
alice: true,
david: true,
// ...
}
}
我有以下子集合结构:
/projects/{projectId}/documents/{documentId}
其中每个文档都有一个 access
映射用于检查每个文档的安全规则:
{
title: "A Great Story",
content: "Once upon a time ...",
access: {
alice: true,
bob: false,
david: true,
jane: false
// ...
}
}
如何设置安全规则:
match /{path=**}/documents/{documentId} {
allow list, get: if resource.data.access[request.auth.uid] == true;
}
当我想查询 alice 可以跨所有项目访问的所有文档时:
db.collectionGroup("documents").where(`access.${uid}`, "==", true);
我收到一条错误消息,提示我需要为 access.alice
、access.david
等创建集合组索引
如何解决集合组查询的索引编制问题?
如 https://cloud.google.com/firestore/docs/query-data/queries#collection-group-query 所述,“在使用集合组查询之前,您必须创建一个支持您的集合组查询的索引。您可以通过错误消息、控制台或 Firebase CLI 创建索引."
在这种情况下,您需要在访问映射 (https://cloud.google.com/firestore/docs/query-data/indexing#add_a_single-field_index_exemption)
上启用 CollectionGroup 查询如@Jim 所述,您必须为其创建索引。
如果你不想深入了解它,你可以直接捕获错误,它会直接 link 来创建一个,如下所示:
db.collectionGroup("documents").where(`access.${uid}`, "==", true).get().then((snap) => {
//
}).catch((e) => console.log(e))
文档中提到的其他方式包括:
Before using a collection group query, you must create an index that supports your collection group query. You can create an index through an error message, the console, or the Firebase CLI.
作为索引的快速概述,有两种类型 - 复合索引(用于将多个字段连接在一起)或单字段索引。默认情况下,对于普通集合查询,单字段索引会自动为文档的每个字段创建,而对于集合组查询则禁用。如果字段的值是数组,则该数组的值将添加到 Array Contains 索引中。如果字段的值是原始值(字符串、数字、时间戳等),文档将添加到该字段的 Ascending 和 Descending 索引.
要为集合组查询启用 access
字段查询,您必须创建索引。虽然您可以在进行查询时收到的错误消息中单击 link,但这只会为您正在查询的用户添加索引(例如 access.alice
、access.bob
,等等).相反,您应该使用 Firebase Console 告诉 Cloud Firestore 为 access
创建索引(这将为其每个子项创建索引)。打开控制台后,使用“添加豁免”按钮(将“豁免”的这种用法视为“覆盖默认设置”)定义新的索引规则:
在第一个对话框中,使用这些设置:
Collection ID: "documents"
Field Path: "access"
Collection: Checked ✔
Collection group: Checked ✔
在第二个对话框中,使用这些设置:
Collection Scope | Collection Group Scope | |
---|---|---|
Ascending | Enabled | Enabled |
Descending | Enabled | Enabled |
Array Contains | Enabled | Enabled |
在你的安全规则中,你还应该在做相等之前检查目标用户是否在access
映射中。访问丢失的 属性 时会抛出“属性 在对象上未定义。”拒绝访问的错误,如果您稍后将语句与 ||
.
要解决此问题,您可以使用:
match /{path=**}/documents/{documentId} {
allow list, get: if request.auth.uid in resource.data.access
&& resource.data.access[request.auth.uid] == true;
}
或在找不到所需键时提供后备值:
match /{path=**}/documents/{documentId} {
allow list, get: if resource.data.access.get(request.auth.uid, false) == true;
}
作为违反规则的示例,假设您希望“职员”用户能够阅读文档,即使他们不在该文档的 access
映射中。
这些规则总是会出错并失败(如果工作人员的用户 ID 不在 access
映射中):
match /{path=**}/documents/{documentId} {
allow list, get: if resource.data.access[request.auth.uid] == true
|| get(/databases/$(database)/documents/users/$(request.auth.uid)).data.get("staff", false) == true;
}
然而,这些规则将起作用:
match /{path=**}/documents/{documentId} {
allow list, get: if resource.data.access.get(request.auth.uid, false) == true
|| get(/databases/$(database)/documents/users/$(request.auth.uid)).data.get("staff", false) == true;
}
附带说明一下,除非您需要查询用户无权访问的文档,否则从访问映射中省略该用户会更简单。
{
title: "A Great Story",
content: "Once upon a time ...",
access: {
alice: true,
david: true,
// ...
}
}