我正在开发一款具有(令人惊讶!)聊天功能的iOS应用。整个应用程序大量使用Firebase工具,对于我正在使用新的Cloud Firestore解决方案的数据库。
目前我正在使用数据库规则来加强安全性,但我在自己的数据模型上苦苦挣扎:)这可能意味着我的数据模型选择不当,但我和#39;除了实施规则部分外,我对它非常满意。
模型的对话部分看起来像这样。在我的数据库的根目录中,我有一个conversations
集合:
/conversations/$conversationId
- owner // id of the user that created the conversation
- ts // timestamp when the conversation was created
- members: {
$user_id_1: true // usually the same as 'owner'
$user_id_2: true // the other person in this conversation
...
}
- memberInfo: {
// some extra info about user typing, names, last message etc.
...
}
然后我在每个对话中都有一个名为消息的子集。消息文档是一个非常简单且只是保存有关每个已发送消息的信息。
/conversations/$conversationId/messages/$messageId
- body
- sender
- ts
会话文档的规则相当简单易行:
match /conversations/{conversationId} {
allow read, write: if resource.data.members[(request.auth.uid)] == true;
match /messages/{messageId} {
allow read, write: if get(/databases/$(database)/documents/conversations/$(conversationId)).data.members[(request.auth.uid)] == true;
}
}
我的问题在于该对话中的消息子集合。上述工作,但我不喜欢在那里使用get()
调用。
每个get()
来电都会执行阅读操作,因此会影响我月底的帐单,请参阅documentation。
如果我正在构建的应用程序将成为一个成功可能会成为一个问题,文档读取的内容实际上是最小的,但每次用户打开对话时这样做似乎有点低效。我非常喜欢我的模型中的子集合解决方案,但不知道如何在这里有效地实现规则。
我打开任何数据模型更改,我的目标是在没有这些get()
调用的情况下评估规则。任何想法都非常受欢迎。
答案 0 :(得分:4)
老实说,我认为您的结构和get
按原样调用是对的。这就是原因:
如果您在子集合中提取大量文档,Cloud Firestore通常足够智能,可根据需要缓存值。例如,如果您要求获取" conversions / chat_abc / messages"中的所有200个项目,则Cloud Firestore将仅执行该操作一次并将其重新用于整个批处理操作。所以你最终会得到201个读数,而不是400个。
作为一般理念,我不喜欢在您的安全规则中优化定价。是的,每次操作最终可能会有一两次额外的读取,但它可能不会以同样的方式给您带来麻烦,比如写一个写得不好的云函数。这些是您优化优化的领域。
答案 1 :(得分:1)
如果要保存这些额外的读取,则实际上可以基于custom claims实施“缓存”。
例如,您可以将用户有权访问的聊天记录保存在自定义声明中的“对话”对象下。请记住,自定义声明的文档中提到的限制为1000个字节。
一种解决方法是,将最新的对话仅保存在自定义声明中,例如前50个对话中。然后在安全规则中可以执行以下操作:
allow read, write: if request.auth.token.conversations[conversationId] || get(/databases/$(database)/documents/conversations/$(conversationId)).data.members[(request.auth.uid)] == true;
如果您在发布消息后已经使用云功能来审核消息,这特别好,那么您所需要做的就是更新自定义声明