简体   繁体   English

Firestore:如何查询文档子集中的角色映射?

[英]Firestore: How to query a map of roles inside a subcollection of documents?

I have the following subcollection structure:我有以下子集合结构:

/projects/{projectId}/documents/{documentId} /projects/{projectId}/documents/{documentId}

Where each document has an access map used for checking security rules for each document:每个文档都有一个用于检查每个文档的安全规则的access映射:

{
  title: "A Great Story",
  content: "Once upon a time ...",
  access: {
    alice: true,
    bob: false,
    david: true,
    jane: false
    // ...
  }
}

How the security rules are set:如何设置安全规则:

match /{path=**}/documents/{documentId} {
      allow list, get: if resource.data.access[request.auth.uid] == true;
}

When I want to query all documents alice can access across all projects:当我想查询 alice 可以跨所有项目访问的所有文档时:

db.collectionGroup("documents").where(`access.${uid}`, "==", true);

I get an error telling me that I need to create a collection group index for access.alice , access.david , etc.我收到一条错误消息,告诉我需要为access.aliceaccess.david等创建集合组索引。

How can I overcome this indexing issue with collection group queries?如何通过集合组查询克服此索引问题?

As noted on https://cloud.google.com/firestore/docs/query-data/queries#collection-group-query "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."https://cloud.google.com/firestore/docs/query-data/queries#collection-group-query 所述“在使用集合组查询之前,您必须创建一个支持您的集合组查询的索引。您可以通过错误消息、控制台或 Firebase CLI 创建索引。”

In this case you'll want to enable CollectionGroup queries on the access map ( https://cloud.google.com/firestore/docs/query-data/indexing#add_a_single-field_index_exemption )在这种情况下,您需要在访问地图上启用 CollectionGroup 查询 ( https://cloud.google.com/firestore/docs/query-data/indexing#add_a_single-field_index_exemption )

As a quick overview of indexes, there are two types - a composite index (used for connecting multiple fields together) or a single-field index.作为索引的快速概述,有两种类型 - 复合索引(用于将多个字段连接在一起)或单字段索引。 By default, single-field indexes are automatically created for each field of a document for ordinary collection queries and disabled for collection group queries.默认情况下,对于普通集合查询,会为文档的每个字段自动创建单字段索引,并为集合组查询禁用单字段索引。 If a field's value is an array, the values of that array will be added to an Array Contains index.如果字段的值是一个数组,则该数组的值将被添加到一个包含数组的索引中。 If a field's value is primitive (string, number, Timestamp, etc), the document will be added to the Ascending and Descending indexes for that field.如果字段的值是原始值(字符串、数字、时间戳等),文档将被添加到该字段的升序降序索引中。

To enable querying of the access field for a collection group query, you must create the index.要为集合组查询启用access字段的查询,您必须创建索引。 While you could click the link in the error message you get when making the query, this would only add an index for the user you were querying (eg access.alice , access.bob , and so on).虽然你可以点击进行查询时,你得到的错误消息中的链接,这只会增加你被查询用户的指标(如access.aliceaccess.bob ,等等)。 Instead, you should use the Firebase Console to tell Cloud Firestore to create the index for access (which will create indexes for each of its children).相反,您应该使用Firebase 控制台告诉 Cloud Firestore 创建用于access的索引(这将为其每个子项创建索引)。 Once you've got the console open, use the "Add Exemption" button (consider this use of "exemption" to mean "override default settings") to define a new indexing rule:打开控制台后,使用“添加豁免”按钮(考虑使用“豁免”来表示“覆盖默认设置”)来定义新的索引规则:

In the first dialog, use these settings:在第一个对话框中,使用以下设置:

Collection ID:      "documents"
Field Path:         "access"

Collection:         Checked ✔
Collection group:   Checked ✔

In the second dialog, use these settings:在第二个对话框中,使用以下设置:

Collection Scope征收范围 Collection Group Scope集合组范围
Ascending上升 Enabled启用 Enabled启用
Descending降序 Enabled启用 Enabled启用
Array Contains数组包含 Enabled启用 Enabled启用

In your security rules, you should also check if the target user is in the access map before doing the equality.在您的安全规则中,您还应该在执行相等操作之前检查目标用户是否在access映射中。 While accessing a missing property throws a "Property is undefined on object."访问缺失的属性时会抛出“对象上的属性未定义”。 error which denies access, this will become a problem if you later combine statements together with ||拒绝访问的错误,如果您稍后将语句与||组合在一起,这将成为一个问题. .

To fix this, you can either use:要解决此问题,您可以使用:

match /{path=**}/documents/{documentId} {
  allow list, get: if request.auth.uid in resource.data.access
                   && resource.data.access[request.auth.uid] == true;
}

or provide a fallback value when the desired key is not found:或在找不到所需键时提供回退值:

match /{path=**}/documents/{documentId} {
  allow list, get: if resource.data.access.get(request.auth.uid, false) == true;
}

As an example of the rules breaking, let's say you wanted a "staff" user to be able to read a document, even if they aren't in that document's access map.作为违反规则的示例,假设您希望“员工”用户能够阅读文档,即使他们不在该文档的access映射中。

These rules would always error-out and fail (if the staff member's user ID wasn't in the access map):这些规则总是会出错并失败(如果员工的用户 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;
}

whereas, these rules would work:然而,这些规则会起作用:

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;
}

As a side note, unless you need to query for documents where a user does not have access to it, it is simpler to simply omit that user from the access map.作为旁注,除非您需要查询用户无权访问的文档,否则从访问映射中简单地省略该用户会更简单。

{
  title: "A Great Story",
  content: "Once upon a time ...",
  access: {
    alice: true,
    david: true,
    // ...
  }
}

You would have to create an index for it as mentioned by @Jim.如@Jim 所述,您必须为它创建一个索引。 If you don't want to get much into it, you can just catch the error and it'll have a direct link to to create one as shown below:如果您不想深入了解它,您可以捕获错误,它会有一个直接链接来创建一个,如下所示: 在此处输入图片说明


db.collectionGroup("documents").where(`access.${uid}`, "==", true).get().then((snap) => {
  //
}).catch((e) => console.log(e))

Other ways as mentioned in the documentation include:文档中提到的其他方法包括:

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.您可以通过错误消息、控制台或 Firebase CLI 创建索引。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何查询按子集合中定义的角色过滤的 Firestore 文档 - How to query Firestore documents filtered by roles defined in a subcollection Firestore:如何查询文档集合中的地图对象? - Firestore: How to query a map object inside a collection of documents? Firestore 如何访问文档中的子集合 map (Flutter) - Firestore how to access subcollection inside docs map (Flutter) 如何进行 collectionGroup 查询但获取子集合所在的文档? - how do I do a collectionGroup query but get the documents that subcollection is inside of? 如何在Firestore子集合中获取所有文档 - How to get all documents in a firestore subcollection 如何在 Firebase Firestore 的每个文档的子集合中获取文档? - How can I get documents inside a subcollection in every document in Firebase Firestore? 如何获取 Firestore 集合中所有文档的子集合的特定文档? - How to get specific Documents of a Subcollection of all Documents in a Collection in Firestore? 获取 Firestore 中子集合内所有文档的特定值的列表 - Get list of a specific value of all the documents inside a subcollection in Firestore 我可以在 Cloud Firestore 的子集合中查询和检索文档的字段值吗? - Can I query and retrieve Documents' field values in Subcollection in Cloud Firestore? 如何使用 reactjs 在 Firestore 中获取子集合? - How to get subcollection inside firestore using reactjs?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM