Firebase requête si l'enfant de l'enfant contient une valeur

la structure du tableau est la suivante:

  • chats
  • -- > randomId
  • -- > -- > participants
  • -->-->--> 0: 'nom1 '
  • -->-->--> 1: 'nom2'
  • -- > -- > chatItems

etc

ce que j'essaie de faire est d'interroger la table des chats pour trouver tous les chats qui tiennent un participant par un passé dans nom d'utilisateur de la chaîne.

Voici ce que j'ai jusqu'à présent:

 subscribeChats(username: string) {
    return this.af.database.list('chats', {
        query: {
            orderByChild: 'participants',
            equalTo: username, // How to check if participants contain username
        }
    });
 }
34
demandé sur Frank van Puffelen 2016-11-17 16:46:42

1 réponses

votre structure de données actuelle est excellente pour rechercher les participants d'un chat spécifique. Ce n'est toutefois pas une très bonne structure pour chercher l'inverse: les conversations dans lesquelles un utilisateur participe.

quelques problèmes ici:

  • vous êtes le stockage d'un set comme un tableau
  • vous pouvez seulement l'index sur les chemins fixes

Set vs array

un chat peut avoir plusieurs participants, donc vous modélisez ceci comme un tableau. Mais ce n'est pas la structure de données idéale. Probablement chaque participant ne peut être dans le chat une fois. Mais en utilisant un tableau, j'aurais pu:

participants: ["puf", "puf"]

, C'est clairement pas ce que vous avez à l'esprit, mais la structure de données permet. Vous pouvez essayer de sécuriser cela dans le code et les règles de sécurité, mais ce serait plus facile si vous commenciez avec une structure de données qui correspond implicitement à votre modèle mieux.

Ma règle d'or: si vous vous trouvez écrire array.contains() , vous devriez être en utilisant un ensemble .

un ensemble est une structure où chaque enfant peut être présent au plus une fois, donc il protège naturellement contre les doublons. Dans Firebase vous modéliseriez un ensemble comme:

participants: {
  "puf": true
}

le true ici est vraiment juste une valeur fictive: la chose importante est que nous avons déplacé le nom à la clé. Maintenant, si Je voudrais essayer de rejoindre cette conversation à nouveau, il serait un noop:

participants: {
  "puf": true
}

Et quand tu allais rejoindre:

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

c'est la représentation la plus directe de votre exigence: une collection qui ne peut contenir chaque participant qu'une seule fois.

vous ne pouvez indexer que les propriétés connues

avec la structure ci-dessus, vous pourrait requête pour les chats que vous êtes avec:

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

le problème est que cela nécessite que vous définissiez un index sur 'participants / john":

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

cela va fonctionner et effectuer grand. Mais maintenant chaque fois que quelqu'un de nouveau rejoint l'application de chat, vous aurez besoin d'ajouter un autre index. C'est clairement pas une évolutive modèle. Nous aurons besoin de changer notre structure de données pour permettre la requête que vous voulez.

Inverser l'index-tirer les catégories vers le haut, aplatir l'arbre

Deuxième règle empirique: modéliser vos données pour refléter ce que vous montrez dans votre application .

comme vous cherchez à montrer une liste de salons de discussion pour un utilisateur, stockez les salons de discussion pour chaque utilisateur:

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

Maintenant, vous pouvez simplement déterminer votre liste de salons de chat avec:

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

et ensuite boucler les touches pour obtenir chaque chambre.

Vous aimerez avoir deux listes dans votre app:

  • la liste des salles de chat pour un utilisateur spécifique
  • la liste des participants dans un salon de discussion spécifique

dans ce cas, vous aurez aussi les deux listes dans la base de données.

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

j'ai tiré les deux listes au niveau supérieur de l'arbre, puisque Firebase recommande contre les données de nidification.

avoir les deux listes est tout à fait normal dans NoSQL solution. Dans l'exemple ci-dessus, nous appellerions userChatrooms l'indice inversé de chatroomsUsers .

56
répondu Frank van Puffelen 2018-09-26 14:20:07