Angular 如果子级的子级包含值,则Firebase查询
该表的结构如下:Angular 如果子级的子级包含值,则Firebase查询,angular,firebase,firebase-realtime-database,angularfire2,Angular,Firebase,Firebase Realtime Database,Angularfire2,该表的结构如下: 聊天 -->随机的 -->-->参与者 -->-->-->0:“名称1” -->-->-->1:“名称2” -->-->聊天项目 等 我试图做的是查询chats表,通过传入的用户名字符串查找包含参与者的所有聊天 以下是我到目前为止的情况: subscribeChats(username: string) { return this.af.database.list('chats', { query: { orderByChi
- 聊天
- -->随机的
- -->-->参与者
- -->-->-->0:“名称1”
- -->-->-->1:“名称2”
- -->-->聊天项目
subscribeChats(username: string) {
return this.af.database.list('chats', {
query: {
orderByChild: 'participants',
equalTo: username, // How to check if participants contain username
}
});
}
您当前的数据结构非常适合查找特定聊天的参与者。然而,它不是一个很好的结构来查找相反的内容:用户参与的聊天 这里有几个问题:
- 您正在将集合存储为数组
- 只能在固定路径上建立索引
participants: ["puf", "puf"]
这显然不是您想要的,但数据结构允许这样做。您可以尝试在代码和安全规则中对此进行保护,但如果您从一个隐式地更好地匹配您的模型的数据结构开始,这将更加容易
我的经验法则:如果您发现自己正在编写array.contains()
,那么应该使用set
集合是一种结构,每个子对象最多只能出现一次,因此它自然可以防止重复。在Firebase中,您可以将集合建模为:
participants: {
"puf": true
}
这里的true
实际上只是一个伪值:重要的是我们已经将名称移动到了键。现在,如果我再次尝试加入此聊天,它将是一个noop:
participants: {
"puf": true
}
当你加入时:
participants: {
"john": true,
"puf": true
}
这是对您的需求最直接的表示:集合只能包含每个参与者一次
只能为已知属性编制索引
使用上述结构,您可以查询您正在使用的聊天:
ref.child("chats").orderByChild("participants/john").equalTo(true)
问题是,这需要在“参与者/john”上定义索引:
这将起作用并表现出色。但现在每次有新用户加入聊天应用程序时,您都需要添加另一个索引。这显然不是一个可扩展的模型。我们需要更改数据结构以允许您进行所需的查询
反转索引-向上拉类别,使树变平
第二条经验法则:对数据进行建模,以反映您在应用程序中显示的内容
由于您希望为用户显示聊天室列表,请存储每个用户的聊天室:
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解决方案中是完全正常的。在上面的示例中,我们将用户聊天室
作为聊天室用户
的反向索引
云火库
这是Cloud Firestore更好地支持这种查询的一种情况。它的
数组包含运算符允许筛选数组中具有特定值的文档,而数组删除允许您将数组视为一个集合。有关这方面的更多信息,请参阅。这是一个很棒的解释。我将数据存储在类似于此,它允许我从用户列表中获取聊天室,或从聊天室成员中获取用户。但它不允许对我所属的聊天室观察.childChanged
。如果我尝试为聊天室设置观察者,其中成员/myId=true
,那么我会得到未指定的索引错误。你会怎么做你打算怎么做?我有一个问题贴在这里:@frank van puffelen引用了你最后的代码片段,假设我是“user1”“我会拿到我所属聊天室的所有钥匙。然后,对于每个聊天室键,我获取完整的聊天室对象,并在列表中显示聊天室列表。这很好,但是,如果我还需要访问聊天室中的完整用户对象呢。看起来很奇怪,我必须为每个聊天室中的每个用户执行另一个for循环(2级嵌套for循环!)获取数据。有更好的办法吗?
chatroomUsers
chatroom1
user1: true
user2: true
chatroom2
user1: true
user3: true
userChatrooms
user1:
chatroom1: true
chatroom2: true
user2:
chatroom1: true
user2:
chatroom2: true