如果子项的子项包含值,则为Firebase查询

时间:2016-11-17 13:46:43

标签: angular firebase firebase-realtime-database angularfire2

表的结构是: 聊天记录 - > randomId - > - >参与者 - &GT - → - →; 0:' name1' - &GT - → - →; 1:' name2' - > - > chatItems 等等 我想要做的是查询聊天表,找到通过传入的用户名字符串保存参与者的所有聊天。 这是我到目前为止:  subscribeChats(用户名:字符串){     return this.af.database.list(' chats',{         查询:{             orderByChild:'参与者',             equalTo:username,//如何检查参与者是否包含用户名         }     });  }

1 个答案:

答案 0 :(得分:68)

您当前的数据结构非常适合查找特定聊天的参与者。然而,查找逆变量并不是一个非常好的结构:用户参与的聊天。

这里有一些问题:

  • 您将存储为数组
  • 您只能在固定路径上编制索引

设置与阵列

聊天可以有多个参与者,因此您将其建模为数组。但这实际上并不是理想的数据结构。可能每个参与者只能在聊天中一次。但是通过使用数组,我可以:

participants: ["puf", "puf"]

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

我的经验法则:如果您发现自己正在撰写array.contains(),那么您应该使用一套

一个集合是一个结构,每个孩子最多可以出现一次,因此它自然可以防止重复。在Firebase中,您可以将集合建模为:

participants: {
  "puf": true
}

这里的true实际上只是一个虚拟值:重要的是我们将名称移到了键上。现在,如果我再次尝试加入此聊天,那将是一个noop:

participants: {
  "puf": true
}

当你加入时:

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

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

您只能索引已知属性

通过上述结构,您可以查询您所处的聊天内容:

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

问题是这需要在`participant / john'上定义一个索引:

{
  "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的反向索引。

Cloud Firestore

这是Cloud Firestore更好地支持此类查询的情况之一。其array-contains运算符允许在数组中具有特定值的过滤器文档,而arrayRemove允许您将数组视为一组。有关详情,请参阅Better Arrays in Cloud Firestore