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
的倒排索引。