firebase - 带有子集合的 Firestore 查询规则
问题描述
我有一个关于 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”,并且根据“文档”中的时间戳,他们请求的时间无效,这是否会因为父集合规则而自动拒绝?
如果没有,我已经看到您可以使用与 get 结合使用的功能来访问其他文档,但这似乎很浪费,因为这将收取我阅读的费用。
例如这样做
function getTopLevelDocData() {
return get(/databases/$(database)/documents/Collection/$(documentWildcard)).data
}
我能想到的唯一其他方法是将时间戳写入子集合中的每个文档......但这可能很难跟踪。
任何帮助表示赞赏:)
- - 更新
我刚刚尝试过,它确实允许读取“Document1”如果我不调用检查“Document1”规则中“Document”时间戳的函数......只是为了澄清读取“Document1”或“Document2”只有1额外阅读,因为它必须检查“文档”时间戳?
--- 第二次更新
想象一下上面示例中的“文档”实际上具有文档名称“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}
}
}
解决方案
我刚刚尝试过,它确实允许读取如果我不调用该函数...
您没有显示您将read
问题中显示的安全规则应用于哪些集合,但请注意resource.data
指向resource
您正在尝试阅读的内容,因此如果您在子集合文档中没有相应的字段,它将不适用于这些文档。
读取“Document1”或“Document2”是否只会额外读取 1 次,因为它必须检查“Document”时间戳?
是的,每次评估安全规则时都会读取一个文档。
第二次更新后更新
是的,通过使用通配符语法,您可以使用父级的文档 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())
andstring(request.time.month())
将在 10 月之前的几个月内返回一个字符的字符串,例如 8 月的 8 月或 10 之前的几天。您可以使用 YYYY-MD 或微调安全规则来处理这个问题。
推荐阅读
- javascript - Django响应将json设置为cookie
- java - 如何在Nodejs(如Java)中将字符串转换为字节数组
- python - 如何反转标签的 One-Hot Encoding 以评估 ML/DL 模型?
- flutter - 如何在 Flutter 中通过卡片点击打开另一个页面
- javascript - 是否有更新实时烛台图表的示例?
- nginx - 在 Nginx 中为某些 IP 禁用缓存控制
- javascript - 如何使用 parsimmon.js 解析 jsDoc 注释?
- c++ - 当调用函数中捕获到异常时,如何确保在函数内删除数组?
- python - DJANGO REST FRAMEWORK 中的注册问题
- spring - 在哪个场景中,我们在 applicationContext 上调用 refresh(),start() 和 refresh() 方法有什么区别?