Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/firebase/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Angular 如果子级的子级包含值,则Firebase查询_Angular_Firebase_Firebase Realtime Database_Angularfire2 - Fatal编程技术网

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”
  • -->-->聊天项目

我试图做的是查询chats表,通过传入的用户名字符串查找包含参与者的所有聊天

以下是我到目前为止的情况:

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

您当前的数据结构非常适合查找特定聊天的参与者。然而,它不是一个很好的结构来查找相反的内容:用户参与的聊天

这里有几个问题:

  • 您正在将集合存储为数组
  • 只能在固定路径上建立索引
集合vs数组 聊天可以有多个参与者,因此您将其建模为一个数组。但这实际上并不是理想的数据结构。可能每个参与者只能参与一次聊天。但通过使用数组,我可以:

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