Implementar consultas en tiempo real con Firestorm/Firestore te permite mostrar cambios sin recargar ni hacer polling. Con una suscripción a la colección, la base de datos notifica inserciones, actualizaciones y eliminaciones. Así, el blog se mantiene ágil y sincronizado, mejorando el rendimiento y la experiencia.
¿Qué es real time en Firestorm y por qué mejora el rendimiento?
La idea clave: la base de datos envía eventos cuando cambian los datos. No necesitas consultar constantemente. Otras aplicaciones pueden insertar, actualizar o borrar, y tu app recibe el aviso al instante.
Suscripción a una colección con onSnapshot.
Recepción automática de cambios: agregar, modificar o eliminar documentos.
Menos consultas repetitivas y renderizado más eficiente.
¿Cómo funciona la suscripción con onSnapshot?
Se obtiene la instancia de Firestorm/Firestore, se apunta a la colección "post" y se registra onSnapshot. Este método entrega una copia de los datos en una variable tipo querySnapshot cada vez que se produce un cambio.
Te suscribes a la colección.
Recibes un snapshot actualizado en cada evento.
Procesas los documentos y actualizas la interfaz.
¿Qué datos entrega querySnapshot y cómo tratarlos?
querySnapshot representa el estado actual de la consulta: si está vacío, se muestra un "post vacío" para motivar a crear contenido; si trae documentos, se recorre con foreach y se renderiza cada post con una plantilla HTML.
Verificación de vacío para decidir qué mostrar.
Recorrido con foreach para múltiples documentos.
Limpieza del listado antes de repintar.
¿Cómo pintar y actualizar los posts en tiempo real?
El flujo recomendado: vaciar el contenedor de posts, comprobar si hay datos, y luego construir el HTML con una función de plantilla. Si no hay elementos, se inserta un post genérico (el "post vacío").
¿Cómo manejar el caso sin datos y el post vacío?
Si querySnapshot no contiene documentos, se agrega el resultado de la función "obtener post vacío" para invitar a publicar. Esto asegura una interfaz útil incluso sin contenido.
Mensaje motivador mediante un post genérico.
Interfaz consistente sin listas vacías.
¿Cómo construir el HTML con una plantilla?
Cada documento se pasa a una función que devuelve el template HTML del post. Los campos provienen de post.data() (un objeto JSON): autor, título, descripción, videolink, imágelink y fecha.
Acceso a datos con post.data().
Transformación de fecha: de timestamp a legible con utilidad.estática.
Inserción del HTML en el contenedor de posts.
// Suscripción a todos los posts (esqueleto basado en el flujo descrito)Firestorm.collection('post').onSnapshot((querySnapshot)=>{// 1) Limpiar la lista antes de repintar.// limpiarPosts();if(querySnapshot.empty){// 2) Agregar el post vacío cuando no hay datos.const htmlVacio =obtenerPostVacio();// render(htmlVacio);return;}// 3) Recorrer y pintar cada post. querySnapshot.forEach((post)=>{const data = post.data();// autor, título, descripción, videolink, imágelink, fecha.// 4) Formatear fecha: timestamp -> Date -> string legible.const fechaLegible = utilidad.obtenerFecha(data.fecha.toDate());// 5) Construir HTML con la plantilla.const postHTML =obtenerPostTemplate({autor: data.autor,titulo: data.titulo,descripcion: data.descripcion,videolink: data.videolink,imagelink: data.imagelink,fecha: fechaLegible,});// 6) Agregar al contenedor del blog.// render(postHTML);});});
La función de utilidad convierte timestamp con toDate() y formatea la salida para el usuario.
La plantilla HTML reemplaza valores y devuelve el bloque listo para insertar.
¿Cómo filtrar “Mis posts” con where por autor?
Para ver solo los posts del usuario autenticado, se usa un filtro por el campo "autor". Así, "Mis posts" muestra únicamente documentos cuyo autor coincide con el correo del usuario.
Filtro por igualdad con where.
Registro del escucha en tiempo real para ese subconjunto.
Integración con la acción de clic en "Mis posts".
¿Cómo registrar el escucha al hacer clic en mis posts?
Al activar la opción "Mis posts" y con el usuario autenticado, se llama a la función que suscribe la consulta filtrada por email. También se reutiliza el registro al visitar "Todos los posts" para escuchar toda la colección.
// Consulta en tiempo real solo para el autor indicado.functionconsultarPostPorUsuario(email){Firestorm.collection('post').where('autor','==', email).onSnapshot((querySnapshot)=>{// Limpiar y repintar como en la consulta general.if(querySnapshot.empty){const htmlVacio =obtenerPostVacio();// render(htmlVacio);return;} querySnapshot.forEach((post)=>{const data = post.data();const fechaLegible = utilidad.obtenerFecha(data.fecha.toDate());const postHTML =obtenerPostTemplate({autor: data.autor,titulo: data.titulo,descripcion: data.descripcion,videolink: data.videolink,imagelink: data.imagelink,fecha: fechaLegible,});// render(postHTML);});});}
Al editar un título y actualizarlo, el cambio se refleja en real time sin relanzar la consulta.
"Todos los posts" escucha la colección completa; "Mis posts" aplica el filtro por autor.
¿Tienes dudas o quieres compartir cómo implementaste tu suscripción con onSnapshot y el filtro por autor? Escribe tus comentarios y cuéntanos tu caso.
Estos tutoriales (algunos en ingles 🇺🇸) son muy útiles para complementar lo que aprendimos en la clase y ver las otras formas (o no 😅) de consumir la información de Firetore en tiempo real con otros proyectos 👍:
Firebase Firestore Tutorial - Real-time Data
Obtener actualizaciones en tiempo real con Cloud Firestore
Gracias bro!
El curso esta fuera de tiempo y la enseñanza es muy confusa.. No estoy satisfecho con este curso..
yo veo que todo aplica al firebase de hoy, tal vez es por que hay que entender el proyecto que estan usando de base, lo mejor seria que aplicaras los conocimientos en un proyecto propio
Concuerdo, yo estoy siguiendo el curso pero con un proyecto propio y a 1.75x y todo super bien. Sin embargo, veo que seguir el curso con el proyecto base que tiene, si es un poco confuso.
Les dejo una actualización en el archivo de util.js
Puesto que la fecha no se muestra con el formato correcto NAN/NAN/NAN a consecuencia de cambios en en la API de firestore
classUtilidad{staticobtenerFecha(timeStamp){// El cambio es llamar al atributo secondsconst d =newDate(timeStamp.seconds)console.log(timeStamp);console.log(d);let month =''+(d.getMonth()+1)let day =''+ d.getDate()let year = d.getFullYear()if(month.length<2) month ='0'+ month
if(day.length<2) day ='0'+ day
return[day, month, year].join('/')}}
A la fecha de escribir este comentario. Se debe dejar como esta escrito en los documentos del repo sin agregar ".seconds"
Eso de que Firebase nos notifique cada vez que hay algún cambio en las BDs en vez de nosotros consultar cada segundo (haciendo nuestra aplicación cada vez más lenta) es mágico 😍🔥🎉.
Hola, tu decides si quieres recibir la info en real time y en algunas ocasiones es más rápido que estar siempre consultando
Refused to display 'https://www.youtube.com/watch?v=kpcjBD1XDwU'in a frame because it set'X-Frame-Options' to 'sameorigin'.
Como puedo corregirlo?
Prueba con otro video. Quizás este esté restringido para correr fuera de Youtube.
Nada Fredy, intenté con varios videos y sucedió lo mismo, con una imagen funciona perfectamente.
La nueva web es muchísimo más dinámica que hace tan solo algunos años
Tuve que quitar el constructor de la clase Post y llevarlo al archivo general.js para poder crear otro post pues me aparecio un error en consola que decia que la firestore ya habia sido inicializado y los "settings" ya habian seteados y no podian modificarse.
$(()=>{............firebase.initializeApp(varConfig);db = firebase.firestore();// recupera datos datetime(convierte) a timestampconst settings ={timestampsInSnapshots:true,enablePersistence:true};db.settings(settings);$('#btnInicioSesion').click(()=>{...............)
Deduzco que al existir al menos un post éste se mostraba en el front y por lo tanto, se inicializaba firestore. Por ello el error y algún cambio en la API. Puesto que, cuando el profesor lo ejecutó, todo era correcto.
<------------------------->
Añado un pequeño "hack" que realicé para poder mostrar los videos de youtube:
Click derecho en el video a insertar y seleccionar copiar código de inserción.
Copiar el código en algún lugar(bloc de notas, editor de codigo, etc) y copiar el src que nos brindará youtube para usar en el iframe.
Usar para registrar el video al crear un post y/o actualizar en firestore en caso ya se haya creado el post y tengan problemas con el video.
Casi, lo olvidó. En la clase Post reemplazar this.db por db
Muchas gracias!
Ahora para obtener los posts es así
this.db.collection('posts').get().then(....
websockets VS DataSnapshot
que es mejor para un chat !?
Websockets mil veces, ya que vas a necesitar consultar datos cada vez que haya alguno nuevo
Para React
Pueden utilizar un useEffect para suscribirse y enviar estos datos al estado, también retorno el, id del documento para utilizarlo como key.
const[realTimeData, setRealTimeData]=useState([])//Real time queriesuseEffect(()=>{const unsubscribe =DB.collection('products').onSnapshot(querySnapShot=>{const data = querySnapShot.docs.map(doc=>{return{id: doc.id,...doc.data()}})setRealTimeData(data)})//remember to unsubscribe from your realtime listener on unmount or you will create a memory leakreturn()=>unsubscribe()},[])```
Si les sale algún error con los videos de YouTube, asegurense que cuando llenaron en el formulario el link del video, tenga el formato:
https://www.youtube.com/embed/id-del-video
Ya que se necesita /embed/ para la inserción a HTML.
se menciona que usar 'realtime' 'mejora' el rendimiento.. estoy en desacuerdo con esa frase.. dirai que mejora la experiencia del usuario (=datos en tiempo real) y facilita el trabajo del programdor (no tiene que hacer las llamadas de consulta a mano).. pero estar 'escuchando' cambios a la base de datos AUMENTA la carga al servidor (imagina eso x 1000 usuarios que estuvieran usando tu aplicacion al mismo tiempo).. por supuesto esto es oro para google, porque si hace un cambio se traduce en x1000 consultas automaticas en el 'fondo' para mantener a tus usuarios actualizados... ojo con eso, porque se paga por consultas.. si no se es cuidadoso, esta "muletilla" se puede convertir en un agujero economico..
Cual es el pluggin para intelisense de JS ? para que al crear una funcion en otro archivo y usarlo, siempre entienda que funcion es ?
Hola, no entendí, puedes explicar mejor??
¡Hola Roberto! Cuando se utiliza VSCode ya tiene integrado un autocompletado, lo que debes hacer es importar el archivo de .js a el archivo que estás utilizando para que puedas usarlo ahí
esto parece brujeria!!! jejeje
Que tan seguro es si filtramos por "uid" ???
Estarías consultando por el ID básicamente, no tendrías ningún tipo de problema solo que no le deberías mostrar esa información a ningún usuario
Esta parte del curso parece ser una de las mejores! Me quede anonajado!
esta capacidad es super interesante por el poco esfuerzo de implementacion requerido.. pero cuidado.. si tienes X usuarios, cada CRUD que alguien haga se traducira en X consultas por usuario que este usando la aplicacion en ese momento .. asi que si tienes 1000 usuarios usando el app y alguien inserta un post, se disparan 1000 consultas a tu cuota?
$$$$$ si no se maneja con cuidado..
Si su consola les llena de errores, desactiven adBlock