Firebase查询子项的子项是否包含值 [英] Firebase query if child of child contains a value

查看:157
本文介绍了Firebase查询子项的子项是否包含值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

表格的结构是:


  • 聊天

  • - > randomId li>
  • - > - >参与者
  • - > - > - > 0:'name1'

  • - > - > - > 1:'name2'

  • - > - > chatItems



  • etc



    我正在尝试查询聊天表,通过传入的用户名字符串查找所有通过聊天记录参与者的聊天记录。



    这是我到目前为止:

      subscribeChats(username :string){
    return this.af.database.list('chats',{
    query:{
    orderByChild:'participants',
    equalTo:username,// How检查参与者是否包含用户名
    }
    });


    解决方案

    / p>


    • 您将集合存储为数组
    • 只有固定路径上的索引


      设置数组



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

       参与者:[puf,puf] 

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



      我的经验法则:如果您发现自己正在编写 array.contains(),则应该使用set

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

       参与者:{
      puf:true
      }

      true 虚拟价值:重要的是我们已经把名字移到了关键字上。

       参与者:{
      puf:true
      }

      当你加入时:



      $ $ p $ 参与者:{
      john:true,
      puf:true
      }

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

      您只能索引固定路径



      通过上述结构,您可以查询您的聊天记录($)
      $ b

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

      问题在于,这要求您比`participants / john定义一个索引:

        {
      rules:{
      chats:{
      $ chatid:{
      参与者:{
      .indexOn:[john,puf]
      }
      }
      }
      }
      }

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

      反转索引 - 拉动类别,扁平化树



      第二条经验法则:为您的数据建模,以反映您在应用中展示的内容



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

        userChatrooms:{
      john:{
      chatRoom1:true,
      chatRoom2:true
      },
      puf:{
      chatRoom1:true $ b $ chatRoom3:

      $ b $ $ $ $ $ $ b

      现在您可以简单地确定您的聊天室列表:

        ref.child(userChatrooms)。child (john)

      然后循环访问每个房间。



      您需要在应用程序中有两个相关的列表: b
      $ b


      • 聊天室列表特定用户

      • 特定聊天室中与会者列表



      在这种情况下,您在数据库中也会有两个列表。

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


      The structure of the table is:

      • chats
      • --> randomId
      • -->--> participants
      • -->-->--> 0: 'name1'
      • -->-->--> 1: 'name2'
      • -->--> chatItems

      etc

      What I am trying to do is query the chats table to find all the chats that hold a participant by a passed in username string.

      Here is what I have so far:

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

      解决方案

      A few problems here:

      • you're storing a set as an array
      • you can only index on fixed paths

      Set vs array

      A chat can have multiple participants, so you modelled this as an array. But this actually is not the ideal data structure. Likely each participant can only be in the chat once. But by using an array, I could have:

      participants: ["puf", "puf"]
      

      That is clearly not what you have in mind, but the data structure allows it. You can try to secure this in code and security rules, but it would be easier if you start with a data structure that implicitly matches your model better.

      My rule of thumb: if you find yourself writing array.contains(), you should be using a set.

      A set is a structure where each child can be present at most once, so it naturally protects against duplicates. In Firebase you'd model a set as:

      participants: {
        "puf": true
      }
      

      The true here is really just a dummy value: the important thing is that we've moved the name to the key. Now if I'd try to join this chat again, it would be a noop:

      participants: {
        "puf": true
      }
      

      And when you'd join:

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

      This is the most direct representation of your requirement: a collection that can only contain each participant once.

      You can only index fixed paths

      With the above structure, you could query for chats that you are in with:

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

      The problem is that this require than you define an index on `participants/john":

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

      This will work and perform great. But now each time someone new joins the chat app, you'll need to add another index. That's clearly not a scaleable model. We'll need to change our data structure to allow the query you want.

      Invert the index - pull categories up, flattening the tree

      Second rule of thumb: model your data to reflect what you show in your app.

      Since you are looking to show a list of chat rooms for a user, store the chat rooms for each user:

      userChatrooms: {
        john: {
          chatRoom1: true,
          chatRoom2: true
        },
        puf: {
          chatRoom1: true,
          chatRoom3: true
        }
      }
      

      Now you can simply determine your list of chat rooms with:

      ref.child("userChatrooms").child("john")
      

      And then loop over the keys to get each room.

      You'll like have two relevant lists in your app:

      • the list of chat rooms for a specific user
      • the list of participants in a specific chat room

      In that case you'll also have both lists in the database.

      chatroomUsers
        chatroom1
          user1: true
          user2: true
        chatroom2
          user1: true
          user3: true
      userChatrooms
        user1:
          chatroom1: true
          chatroom2: true
        user2:
          chatroom1: true
        user2:
          chatroom2: true
      

      I've pulled both lists to the top-level of the tree, since Firebase recommends against nesting data.

      Having both lists is completely normal in NoSQL solutions. In the example above we'd refer to userChatrooms as the inverted index of chatroomsUsers.

      这篇关于Firebase查询子项的子项是否包含值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆