您当前的数据结构非常适合查找特定聊天的参与者。但是,这不是一个很好的反向搜索结构:用户参与的聊天。
这里有几个问题:
您正在将集合存储为数组
您只能在固定路径上建立索引
设置与数组
聊天可以有多个参与者,因此您将其建模为数组。但这实际上不是理想的数据结构。每个参与者可能只能聊天一次。但是通过使用数组,我可以拥有:
participants: ["puf", "puf"]
显然这不是您要考虑的,但是数据结构允许这样做。您可以尝试在代码和安全规则中对此进行保护,但是如果您从一个隐式地与您的模型更好地匹配的数据结构开始,这将更加容易。
我的经验法则:如果发现自己正在写作array.contains(),则应该使用set。
集合是每个孩子最多可以出现一次的结构,因此自然可以防止重复。在Firebase中,您可以将集合建模为:
participants: { "puf": true}在true这里其实只是一个伪值:重要的是我们搬到名称的关键。现在,如果我尝试再次加入此聊天,那就没问题了:
participants: { "puf": true}当您加入时:
participants: { "john": true, "puf": true}这是您需求的最直接表示:一个集合,每个参与者只能包含一次。
您只能索引已知属性
通过上述结构,您可以查询您所在的聊天室:
ref.child("chats").orderByChild("participants/john").equalTo(true)问题是,这需要您在`participants / john“上定义索引:
{ "rules": { "chats": { "$chatid": { "participants": { ".indexOn": ["john", "puf"] } } } }}这将工作并表现出色。但是现在,每次有新朋友加入聊天应用程序时,您都需要添加另一个索引。显然,这不是可扩展的模型。我们需要更改数据结构以允许您需要的查询。
反转索引-向上拉类别,使树变平
经验法则:为数据建模以反映您在应用程序中显示的内容。
由于您要显示用户的聊天室列表,因此请存储每个用户的聊天室:
userChatrooms: { john: { chatRoom1: true, chatRoom2: true }, puf: { chatRoom1: true, chatRoom3: true }}现在,您只需使用以下命令即可确定您的聊天室列表:
ref.child("userChatrooms").child("john")然后遍历键以获取每个房间。
您将在应用程序中有两个相关列表:
特定用户的聊天室列表
特定聊天室的参与者列表
在这种情况下,您还将在数据库中同时拥有两个列表。
chatroomUsers chatroom1 user1: true user2: true chatroom2 user1: true user3: trueuserChatrooms user1: chatroom1: true chatroom2: true user2: chatroom1: true user2: chatroom2: true
由于Firebase建议不要嵌套数据,因此我将两个列表都拉到了树的顶层。
在NoSQL解决方案中拥有两个列表是完全正常的。在上面的示例中,我们将其userChatrooms称为的倒排索引chatroomsUsers。
Cloud Firestore
这是Cloud Firestore对此类查询提供更好支持的情况之一。它的array-contains运算符允许过滤器在数组中具有特定值的文档,而arrayRemove允许您将数组视为一组。



