Tengo una aplicación angular donde estoy consultando mi base de datos de firebase como se muestra a continuación:
constructor() { this.getData(); } getData() { this.projectSubscription$ = this.dataService.getAllProjects() .pipe( map((projects: any) => projects.map(sc=> ({ key: sc.key, ...sc.payload.val() })) ), switchMap(appUsers => this.dataService.getAllAppUsers() .pipe( map((admins: any) => appUsers.map(proj =>{ const match: any = admins.find(admin => admin.key === proj.admin); return {...proj, imgArr: this.mapObjectToArray(proj.images), adminUser: match.payload.val()} }) ) ) ) ).subscribe(res => { this.loadingState = false; this.projects = res.reverse(); }); } mapObjectToArray = (obj: any) => { const mappedDatas = []; for (const key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { mappedDatas.push({ ...obj[key], id: key }); } } return mappedDatas; };Y esto es lo que estoy consultando dentro de dataService:
getAllProjects() { return this.afDatabase.list('/projects/', ref=>ref.orderByChild('createdAt')).snapshotChanges(); } getAllAppUsers() { return this.afDatabase.list('/appUsers/', ref=>ref.orderByChild('name')).snapshotChanges(); }El problema al que me enfrento con esto es que tengo 400 filas de datos que estoy tratando de cargar y tarda alrededor de 30 segundos en cargar, lo cual es increíblemente alto. ¿Alguna idea de cómo puedo consultar esto en un tiempo más rápido?
No tenemos forma de saber si los 30 son razonables, ya que eso depende de la cantidad de datos cargados, la latencia de la conexión y el ancho de banda del cliente, y más factores que no podemos conocer/controlar.
Pero una cosa a tener en cuenta es que está realizando 400 consultas para obtener los usuarios de cada aplicación individual, lo que probablemente no sea excelente para el rendimiento.
Cosas que podrías considerar:
Si tiene experiencia en bases de datos relacionales, esto último puede ser contradictorio, pero en realidad es muy común en el modelado de datos NoSQL y es una de las razones por las que las bases de datos NoSQL escalan tan bien.
Propongo 3 soluciones.
En lugar de devolver todos esos documentos al cargar la aplicación, limítelos a solo 10 y mantenga un registro del último. Luego muestra el 10 (o cualquier número base arbitrario)
Luego haga la interfaz de usuario de tal manera que el usuario tenga que hacer clic en siguiente o cuando el usuario se desplace, busque el siguiente conjunto en función de la información del campo del último documento anterior.
Supongo que necesita mostrar todos los datos obtenidos en alguna tabla o lista, por lo que tener la interfaz de usuario paginando los datos debería tener sentido.
Mostrar alguna interfaz de usuario del cargador en la carga del sitio web. Luego, cuando se hayan obtenido todos los documentos, oculta el cargador y muestra los datos como desee. Puede usar algunas cosas personalizadas para el cargador, o elegir entre cualquiera de las abundantes bibliotecas que existen, o usar mat-progress-spinner de Angular Material
¿Qué sucede si intenta obtenerlos a través de una función en la nube onCall? Será más rápido porque es solo una solicitud que hará la aplicación y las funciones en la nube de Firebase son muy rápidas dentro de los centros de datos de Google.
Dado que la red del usuario puede ser lenta para iterar los documentos, la función de la nube regresará de una vez y eso podría brindarle lo que desea.
Supongo que podría optar por esta opción solo si realmente necesita mostrar todos esos datos a la vez en la carga del sitio web.
Obtener 400 o más documentos cada vez que se carga un sitio web determinado puede ser costoso. Será costoso si el sitio web es visitado con mucha frecuencia por muchos usuarios. El costo de Firebase aumentará a medida que se le cobre por documento leído también.
Verifique si puede optimizar la estructura de datos para evitar obtener tanto.
Esto no se aplica a usted si se trata de un panel de administración o si la obtención de todos los usuarios de esta manera rara vez se realiza, lo que hace que el costo no sea alto en ese caso.