Firebase query if child of child contém um valor

A estrutura da tabela é:

  • chats
  • -> randomId
  • -> -> participantes
  • -> -> -> 0: ‘nome1’
  • -> -> -> 1: ‘nome2’
  • -> -> chatItems

etc

O que estou tentando fazer é consultar a tabela de bate-papos para encontrar todos os bate-papos que contêm um participante de uma cadeia de nome de usuário passada.

Aqui está o que eu tenho até agora:

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

Sua estrutura de dados atual é ótima para procurar os participantes de um bate-papo específico. No entanto, não é uma estrutura muito boa para procurar o inverso: os chats nos quais um usuário participa.

Alguns problemas aqui:

  • você está armazenando um conjunto como um array
  • você só pode indexar em caminhos fixos

Definir matriz de vs

Um bate-papo pode ter vários participantes, então você modelou isso como uma matriz. Mas isso na verdade não é a estrutura de dados ideal. Provavelmente cada participante só pode estar no chat uma vez. Mas usando uma matriz, eu poderia ter:

 participants: ["puf", "puf"] 

Isso claramente não é o que você tem em mente, mas a estrutura de dados permite isso. Você pode tentar proteger isso em código e regras de segurança, mas seria mais fácil se você começasse com uma estrutura de dados que correspondesse implicitamente ao seu modelo.

Minha regra array.contains() : se você se encontrar escrevendo array.contains() , você deve usar um conjunto .

Um conjunto é uma estrutura em que cada criança pode estar presente no máximo uma vez, portanto protege naturalmente contra duplicatas. No Firebase, você modelaria um conjunto como:

 participants: { "puf": true } 

A true aqui é realmente apenas um valor fictício: o importante é que mudamos o nome para a chave. Agora, se eu tentasse entrar neste chat novamente, seria um noop:

 participants: { "puf": true } 

E quando você se inscrever:

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

Essa é a representação mais direta de sua exigência: uma coleção que pode conter apenas um participante uma vez.

Você só pode indexar caminhos fixos

Com a estrutura acima, você pode consultar os bate-papos com os quais está:

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

O problema é que isso requer que você defina um índice em `participants / john”:

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

Isso funcionará e terá um ótimo desempenho. Mas agora, toda vez que alguém entrar no aplicativo de bate-papo, você precisará adicionar outro índice. Isso claramente não é um modelo escalonável. Precisamos alterar nossa estrutura de dados para permitir a consulta desejada.

Inverta o índice – puxe as categorias para cima, achatando a tree

Segunda regra prática: modele seus dados para refletir o que você mostra no seu aplicativo .

Como você deseja mostrar uma lista de salas de bate-papo para um usuário, armazene as salas de bate-papo para cada usuário:

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

Agora você pode simplesmente determinar sua lista de salas de bate-papo com:

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

E depois passe as chaves para pegar cada quarto.

Você gostará de ter duas listas relevantes no seu aplicativo:

  • a lista de salas de bate-papo para um usuário específico
  • a lista de participantes em uma sala de bate-papo específica

Nesse caso, você também terá as duas listas no database.

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

Eu puxei ambas as listas para o nível superior da tree, já que o Firebase recomenda que não sejam nesteds.

Ter ambas as listas é completamente normal nas soluções NoSQL. No exemplo acima, nos referimos a userChatrooms como o índice invertido de userChatrooms de chatroomsUsers de chatroomsUsers .