2016-11-17 122 views
19

表的结构是:火力地堡查询孩子的孩子包含一个值

  • 聊天
  • - > randomId
  • - > - >参与者
  • - > - - > - > 0: 'NAME1'
  • - > - > - > 1: 'NAME2'
  • - > - > chatItems

我想要做的是查询聊天表,找到通过传入的用户名字符串来保存参与者的所有聊天。

这是我到目前为止有:

subscribeChats(username: string) { 
    return this.af.database.list('chats', { 
     query: { 
      orderByChild: 'participants', 
      equalTo: username, // How to check if participants contain username 
     } 
    }); 
} 

回答

32

的几个问题在这里:

  • 你存储一个设置作为固定阵列
  • 你只能索引路径

Set vs array

一个聊天可以有多个参与者,所以你将它建模为一个数组。但这实际上并不是理想的数据结构。可能每个参与者只能进行一次聊天。但通过使用阵列,我可以有:

participants: ["puf", "puf"] 

这显然不是你想到的,但数据结构允许它。你可以尝试在代码和安全规则中保证这一点,但如果你从一个更好地隐含地匹配你的模型的数据结构开始,它会更容易。

我的经验法则:如果你发现自己写作array.contains(),你应该使用一套

一组是每个孩子最多可以出现一次的结构,所以它自然可以防止重复。

participants: { 
    "puf": true 
} 

这里的true真的只是虚值:在火力地堡你会成为一系列的模型,重要的是我们搬到名称的关键。现在,如果我尝试重新加入该聊天,这将是一个空操作:

participants: { 
    "puf": true 
} 

而当你想加入:

participants: { 
    "john": true, 
    "puf": true 
} 

这是你的要求,最直接的表现:一只能包含每个参与者一次的集合。

只能索引固定的路径

通过上述结构,你可以查询聊天记录,你是在用:

ref.child("chats").orderByChild("participants/john").equalTo(true) 

的问题是,这需要比您定义的索引关于`参与者/约翰':

{ 
    "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: true 
userChatrooms 
    user1: 
    chatroom1: true 
    chatroom2: true 
    user2: 
    chatroom1: true 
    user2: 
    chatroom2: true 

由于Firebase建议禁止嵌套数据,我已将两个列表都拉到了树的顶层。

拥有这两个列表在NoSQL解决方案中是完全正常的。在上面的例子中,我们将userChatrooms作为倒数索引chatroomsUsers

+0

这是一个很棒的解释。我有我的数据存储这样,这使我可以从用户的列表抓住聊天室,或从聊天室的成员抓住用户。但它不允许观察'.childChanged'作为我所属的聊天室。如果我尝试为'members/myId = true'设置聊天观察者,那么我得到未指定的索引错误。你会怎么做呢?我有一个问题发布在这里: https://stackoverflow.com/questions/47769044/swift-firebase-using-an-unspecified-index –

+0

@ frank-van-puffelen引用你最后的代码片段,让我们说我是“user1 “并且我取得了我所属的聊天室的所有钥匙。然后为每个聊天室密钥获取完整的聊天室对象,并在列表中显示聊天室列表。不过,如果我还需要访问作为聊天室一部分的完整用户对象,那很好。看起来很奇怪,我必须为每个单个聊天室中的每个单个用户获取另一个for循环(2级嵌套for循环!)来获取该数据。有没有更好的办法? – damirstuhec

相关问题