【问题标题】:Firestore query rules with sub collections带有子集合的 Firestore 查询规则
【发布时间】:2020-12-18 06:06:30
【问题描述】:

我有一个关于 Firestore 规则的问题。

我有一个包含文档的集合...这些文档也有子集合....这些文档也有子集合。

例如

"Collection" -> "Document" -> "Sub-collection-1"  -> "Document1" -> "Sub-collection-2" -> "Document2"
              
(i have changed the names to make it simpler to understand)                                     

我在“文档”中存储了 2 个时间戳,用于控制用户何时能够阅读文档...例如它必须在“startTimestamp”之后但在“endTimestamp”之前。

我的规则如下。

        allow read: if request.auth.uid != null
                  && int(resource.data.startReadTimestamp) < request.time.toMillis()
                  && int(resource.data.endReadTimestamp) > request.time.toMillis()

我的问题是,如果用户尝试阅读子集合文档,例如“Document1”或“Document2”以及他们请求的时间基于“Document”中的时间戳是无效的,这是否会因为父收集规则而自动拒绝?

如果没有,我已经看到您可以使用与 get 结合的功能来访问其他文档,但这似乎很浪费,因为这会收取我阅读的费用。

例如这样做

  function getTopLevelDocData() {
            return get(/databases/$(database)/documents/Collection/$(documentWildcard)).data
        }

我能想到的唯一其他方法是将时间戳写入子集合中的每个文档...但这可能很难跟踪。

任何帮助表示赞赏:)

--- 更新

我刚刚尝试过,它确实允许读取“Document1”如果我不调用检查“Document1”规则中“Document”时间戳的函数...只是为了澄清将读取“Document1”或“Document2”只需额外读取 1 次,因为它必须检查“文档”时间戳?

--- 第二次更新

想象一下上例中的“Document”实际上的文档名称为“2020-08-29”。

如果我尝试读取“Document1”或“Document2”,是否存在不会导致任何文档读取但仍会阻止请求时间戳(转换后)与父“文档”名称不匹配的读取的 Firestore 规则,例如“2020-08-29”

例如,这样的东西可以吗?

match /collection/{document}{
   match /Sub-collection-1/{document1}{

      function transfomRequestTimestampToDate(){
           return request.time.year() + "-" + request.time.month() + request.time.day();
      }

      allow read  if request.auth.uid != null && transfomRequestTimestampToDate() == {document}
   }
}

【问题讨论】:

    标签: firebase google-cloud-firestore


    【解决方案1】:

    我刚刚尝试过,它确实允许读取如果我不调用该函数...

    您没有显示您将问题中显示的read 安全规则应用于哪些集合,但请注意resource.data 指向您尝试阅读的resource,因此如果您不这样做'如果子集合文档中没有相应的字段,则这些文档将无法正常工作。

    读取“Document1”或“Document2”是否只会额外读取 1 次 是否必须检查“文档”时间戳?

    是的,每次评估安全规则时都会读取一个文档。


    第二次更新后更新

    是的,通过使用通配符语法,您可以使用父级的文档 ID 为子级编写规则,例如,如下所示:

    service cloud.firestore {
      match /databases/{database}/documents {
        match /Collection/{parentDocId} {
          allow read: if parentDocId == '2020-08-29';
    
            match /Subcollection1/{SubcollectionDoc} {
               allow read: if parentDocId == '2020-08-29';
            }
        }
      }
    }
    

    如果你想让这个动态,你可以这样做:

    service cloud.firestore {
      match /databases/{database}/documents {
        match /a/{a} {
          allow read: if a == string(request.time.year()) + "-" + string(request.time.month()) + "-" +  string(request.time.day());
    
            match /b/{b} {
                     allow read: if a == string(request.time.year()) + "-" + string(request.time.month()) + "-" +  string(request.time.day());
    
            }
        }
      }
    }
    

    但是,请注意,string(request.time.day())string(request.time.month()) 将在 10 月之前的几个月内返回一个字符的字符串,例如8 月或 10 日之前的几天。您可以使用 YYYY-M-D 或微调安全规则来处理这个问题。

    【讨论】:

    • 无论如何我可以将 request.time 转换为 Firestore 规则中的 YYYY-MM-DD 字符串吗?
    • 你应该可以使用Timestamp方法
    • 太棒了。假设“文档”实际上是一个 YYYY-MM-DD 字符串,我可以通过仅使用时间戳方法并以某种方式使用 $(documentWildcard) 来获取文档名称来避免额外的读取......还是这仍然是一个读取?跨度>
    • 为了能够回答最后一个问题,您需要通过更新您的问题来给出准确的示例(准确的安全规则,包括路径、字段名称和值等......加上准确的查询) .现在,一般来说,如果两个 ReadTimestamp 字段在父文档中,您将需要阅读此文档,因为我认为没有解决方法...
    • 太棒了!非常感谢您的帮助:) .... 我想我可以完全删除我的开始/结束时间戳并使用这种方法。我会尝试按照您的建议找到一种将 0 附加 1-9 天的方法。再次感谢!
    猜你喜欢
    • 2018-07-14
    • 1970-01-01
    • 2018-11-27
    • 2021-01-10
    • 1970-01-01
    • 2019-07-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多