Firebase查询子项的子项是否包含值

表的结构是:

  • 聊天logging
  • – > randomId
  • – > – >参与者
  • – > – > – > 0:'name1'
  • – > – > – > 1:'name2'
  • – > – > chatItems

等等

我想要做的是查询聊天表,find所有通过传入的用户名string保持参与者的聊天。

这是我到目前为止:

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

这里有几个问题:

  • 你将一个集合存储为一个数组
  • 你只能在固定的path上索引

设置vs数组

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

 participants: ["puf", "puf"] 

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

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

一组是每个孩子最多可以存在一次的结构,所以它自然可以防止重复。 在Firebase中,您将模型设置为:

 participants: { "puf": true } 

这里的真实只是一个虚拟的价值:重要的是我们已经把名字移到了关键字上。 现在,如果我再次尝试join这个聊天,这将是一个noop:

 participants: { "puf": true } 

当你join:

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

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

你只能索引固定的path

通过上述结构,您可以查询您所在的聊天logging:

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

问题在于,这要求你比“参与者/约翰”定义一个索引:

 { "rules": { "chats": { "$chatid": { "participants": { ".indexOn": ["john", "puf"] } } } } } 

这将工作和performance很好。 但现在每次有新的人join聊天应用程序,你需要添加另一个索引。 这显然不是一个可扩展的模型。 我们需要改变我们的数据结构来允许你想要的查询。

倒转索引 – 拉起类别,扁平化树

第二条经验法则: 模拟您的数据以反映您在应用中显示的内容

由于您正在寻找为用户显示聊天室的列表,请为每个用户存储聊天室:

 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 

我已经将这两个列表都拉到了树的顶层,因为Firebasebuild议不要嵌套数据。

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