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
}
});
}