Firestore安全规则中调用get()读取当前匹配文档是否额外计费?
get()与resource的计费差异解答 好问题!我来帮你理清这个关于Firestore安全规则计费的关键点:
核心结论
在match /users/{userId}块中调用get(/databases/$(database)/documents/users/$(userId))会产生额外的读取费用,而使用内置的resource变量则不会产生任何额外计费。
具体解释
resource变量的特性resource是Firestore安全规则提供的内置变量,它直接指向当前match块匹配的文档。规则执行时会自动加载这个文档的数据,这个过程不会被计入Firestore的读取费用——相当于规则执行的“基础成本”,不需要额外付费。get()方法的计费逻辑get()方法是主动发起一次文档读取请求,哪怕你读取的就是当前正在检查的文档,这也会被Firestore算作一次独立的读取操作,需要按照标准的文档读取费用计费。哪怕你只调用一次get(),只要不是通过resource获取数据,就会产生额外费用。
你提到的“多次对同一文档的get()仅计费一次”是正确的,但这是指在同一次规则评估流程中多次调用get()读取同一个文档,Firestore会缓存结果,只收取一次费用。但这和用resource免费获取数据是完全不同的概念。
针对你代码的优化建议
你可以把isUserDisabled()函数改成使用resource变量,这样既能实现相同的逻辑,又能避免额外的读取费用:
match /users/{userId} { function isUserDisabled() { // 改用resource直接获取当前文档数据,无额外计费 return resource.data.admin == true; } allow read: if true; allow write: if request.auth.uid == userId && !isUserDisabled(userId); match /posts/{postId} { allow read: if true; allow write: if request.auth.uid == userId && !isUserDisabled(userId); } }
这样修改后,无论是检查用户文档的写权限,还是检查子集合posts的写权限,都不会因为判断用户状态而产生额外的读取费用。
内容的提问来源于stack exchange,提问作者Ratchanan Srirattanamet

