firestore auth angular firebase firebase-database firebase-realtime-database angularfire2

angular - auth - Consulta de Firebase si el hijo del hijo contiene un valor



crud angular firebase (1)

Su estructura de datos actual es excelente para buscar los participantes de un chat específico. Sin embargo, no es una muy buena estructura para buscar lo inverso: los chats en los que participa un usuario.

Algunos problemas aquí:

  • estás almacenando un conjunto como una matriz
  • solo puedes indexar en rutas fijas

Conjunto vs matriz

Un chat puede tener múltiples participantes, por lo que modeló esto como una matriz. Pero esta en realidad no es la estructura de datos ideal. Es probable que cada participante solo pueda estar en el chat una vez. Pero al usar una matriz, podría tener:

participants: ["puf", "puf"]

Claramente, eso no es lo que tiene en mente, pero la estructura de datos lo permite. Puede intentar asegurar esto en código y reglas de seguridad, pero sería más fácil si comienza con una estructura de datos que implícitamente coincida mejor con su modelo.

Mi regla de oro: si te encuentras escribiendo array.contains() , deberías estar usando un conjunto .

Un conjunto es una estructura donde cada niño puede estar presente como máximo una vez, por lo que naturalmente protege contra duplicados. En Firebase modelarías un conjunto como:

participants: { "puf": true }

Lo true aquí es realmente solo un valor ficticio: lo importante es que hemos movido el nombre a la clave. Ahora, si intentara unirme a este chat nuevamente, sería un noop:

participants: { "puf": true }

Y cuando te unías:

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

Esta es la representación más directa de su requerimiento: una colección que solo puede contener a cada participante una vez.

Solo puede indexar propiedades conocidas

Con la estructura anterior, puede consultar los chats en los que se encuentra:

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

El problema es que esto requiere que defina un índice en ''participantes / juan ":

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

Esto funcionará y funcionará muy bien. Pero ahora, cada vez que alguien nuevo se une a la aplicación de chat, deberá agregar otro índice. Claramente, ese no es un modelo escalable. Tendremos que cambiar nuestra estructura de datos para permitir la consulta que desee.

Invierta el índice: arrastre las categorías hacia arriba y aplane el árbol

Segunda regla general: modele sus datos para reflejar lo que muestra en su aplicación .

Como desea mostrar una lista de salas de chat para un usuario, almacene las salas de chat para cada usuario:

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

Ahora puede simplemente determinar su lista de salas de chat con:

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

Y luego pase las llaves para obtener cada habitación.

Te gustaría tener dos listas relevantes en tu aplicación:

  • la lista de salas de chat para un usuario específico
  • la lista de participantes en una sala de chat específica

En ese caso, también tendrá ambas listas en la base de datos.

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

Llevé ambas listas al nivel superior del árbol, ya que Firebase recomienda no anidar datos.

Tener ambas listas es completamente normal en las soluciones NoSQL. En el ejemplo anterior, nos referiremos a userChatrooms como el índice invertido de chatroomsUsers .

Cloud Firestore

Este es uno de los casos en los que Cloud Firestore tiene un mejor soporte para este tipo de consulta. Su operador array-contains permite filtrar documentos que tienen un cierto valor en una matriz, mientras que arrayRemove permite tratar una matriz como un conjunto. Para obtener más información al respecto, consulte Mejores matrices en Cloud Firestore .

La estructura de la tabla es:

  • chats
  • -> randomId
  • -> -> participantes
  • -> -> -> 0: ''nombre1''
  • -> -> -> 1: ''nombre2''
  • -> -> chatItems

etc.

Lo que estoy tratando de hacer es consultar la tabla de chats para encontrar todos los chats que retienen a un participante mediante una cadena de nombre de usuario aprobada.

Esto es lo que tengo hasta ahora:

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