78 votes

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

La structure de la table est la suivante:

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

etc

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

Voici ce que j'ai à ce jour:

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

98voto

Frank van Puffelen Points 16029

Votre structure de données est grande de chercher les participants à un salon de discussion particulier. Il n'est toutefois pas une très bonne structure pour la recherche de l'inverse: les chats que l'utilisateur participe à.

Quelques problèmes ici:

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

Jeu vs tableau

Un chat peut avoir plusieurs participants, de sorte que vous modelé cette comme un tableau. Mais en fait, ce n'est pas l'idéal structure de données. Probablement chaque participant ne peut être dans le chat une fois. Mais en utilisant un tableau, j'ai pu avoir:

participants: ["puf", "puf"]

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

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

Un ensemble est une structure où chaque enfant peut être présent dans la plupart des une fois, de sorte qu'il protège naturellement contre les doublons. Dans Firebase vous auriez un modèle fixé comme suit:

participants: {
  "puf": true
}

L' true ici, c'est vraiment juste une valeur factice: l'important, c'est que nous avons adopté le nom de la clé. Maintenant, si je devais essayer de rejoindre ce chat, il serait un noop:

participants: {
  "puf": true
}

Et quand tu allais rejoindre:

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

C'est le plus direct de la représentation de votre exigence: une collection qui ne peut contenir que chaque participant une fois.

Vous pouvez seulement de l'indice de propriétés connues

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

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

Le problème est que ce besoin de vous définir un index sur les "participants/john":

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

Cela permettra de travailler et d'effectuer des grands. Mais maintenant, à chaque fois que quelqu'un de nouveau se joint à l'application de chat, vous aurez besoin d'ajouter un autre indice. C'est clairement pas une évolutive modèle. Nous allons devoir changer notre structure de données pour permettre à la requête que vous souhaitez.

Inverser l'indice - pull catégories jusqu', l'aplatissement de l'arbre

Deuxième règle de base: le modèle de vos données afin de refléter ce que vous montrez dans votre application.

Puisque vous êtes à la recherche pour afficher la liste des salles de chat pour un utilisateur, de stocker les salles de chat pour chaque utilisateur:

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

Maintenant, vous pouvez tout simplement déterminer votre liste de salles de tchat avec:

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

Et puis une boucle sur les touches pour obtenir chaque chambre.

Vous aimerez avoir deux listes dans votre application:

  • la liste des salles de chat pour un utilisateur spécifique
  • la liste des participants dans une salle de chat

Dans ce cas, vous aurez également 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 de haut-niveau de l'arbre, depuis Firebase recommande à l'encontre de l'imbrication des données.

Avoir deux listes est tout à fait normal dans les solutions NoSQL. Dans l'exemple ci-dessus, nous aurions reportez-vous à l' userChatrooms comme l'index inversé de chatroomsUsers.

Cloud Firestore

C'est un des cas où le Cloud Firestore a un meilleur support pour ce type de requête. Ses array-contains de l'opérateur permet de filtrer les documents qui ont une certaine valeur dans un tableau, alors que arrayRemove permet de traiter un tableau comme un ensemble. Pour en savoir plus, voir Mieux Tableaux dans le Cloud Firestore.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X