Capítulo 8 — Modelado profesional de datos en Cloud Firestore¶
Recursos visuales propuestos¶
Antes de desarrollar el capítulo, conviene seleccionar solo los recursos visuales que aportan valor pedagógico real. En modelado de datos, muchas ideas se entienden mejor con ejemplos comparativos y estructuras visuales simples; solo los casos donde hay que representar relaciones múltiples o flujos de acceso justifican diagramas técnicos.
Imágenes didácticas¶
- Comparación entre SQL y Firestore. Se recomienda como imagen didáctica porque ayuda a mostrar el cambio de mentalidad entre tablas y documentos, normalización estricta y diseño orientado a lecturas.[cite:1][cite:2]
- Ejemplos de colecciones y documentos. Conviene como imagen didáctica porque el lector necesita visualizar cómo se traduce una entidad real de negocio a estructura documental.[cite:1][cite:2]
- Normalización vs desnormalización. Es mejor como imagen didáctica porque la idea central es pedagógica: comparar dos filosofías de diseño y su impacto en consultas, lecturas y mantenimiento.[cite:1][cite:2]
- Ejemplos de relaciones entre entidades. Se recomienda como imagen didáctica porque permite ilustrar uno a uno, uno a muchos y muchos a muchos con casos sencillos antes de pasar al modelo completo del proyecto.[cite:1][cite:2]
- Casos de buen y mal diseño. Conviene como imagen didáctica porque el objetivo es enseñar patrones visuales fáciles de recordar: documento demasiado grande, duplicación razonable, subcolección correcta, etc.[cite:2][cite:3]
Diagramas SVG¶
- Arquitectura del modelo de datos del proyecto del libro. Aquí sí conviene SVG porque habrá múltiples colecciones conectadas, entidades transversales y decisiones jerárquicas que merecen una representación técnica editable y escalable.
- Relaciones entre colecciones. Se recomienda como SVG porque debe mostrar dependencias entre usuarios, perfiles, roles, instituciones, cursos, grupos, clases y tareas, con más precisión que una imagen simple.
- Comparación de distintos modelos documentales. También merece SVG cuando se quiera contrastar dos o tres alternativas estructurales y sus flujos de lectura en una misma vista.[cite:2][cite:3]
- Flujo de acceso a datos según el diseño elegido. Conviene como SVG porque ayuda a representar cómo una decisión de modelado cambia el número de lecturas, el costo y el tiempo de acceso en una pantalla o flujo funcional.[cite:3]
Objetivos de aprendizaje¶
Al finalizar este capítulo, el lector será capaz de:
- Comprender qué significa modelar datos en una base documental y por qué en Firestore el diseño debe partir de los patrones de lectura y no de una traducción directa del mundo relacional.[cite:1][cite:2]
- Diferenciar claramente el modelado SQL del modelado NoSQL documental y entender cuándo conviene normalizar, desnormalizar o duplicar información.[cite:1][cite:2]
- Elegir con criterio entre campos simples, objetos anidados, arrays, subcolecciones y colecciones independientes según el crecimiento esperado de los datos.[cite:2]
- Diseñar estructuras optimizadas para rendimiento, costos y escalabilidad, reduciendo lecturas innecesarias y evitando hotspots o documentos demasiado grandes.[cite:2][cite:3]
- Modelar relaciones uno a uno, uno a muchos y muchos a muchos en Firestore con un enfoque profesional y pragmático.
- Construir paso a paso un modelo de datos sólido para el proyecto oficial del libro antes de escribir una sola línea de código.
Introducción¶
Modelar datos significa decidir cómo se representará la realidad del negocio dentro de la base de datos. No es una tarea administrativa ni un paso burocrático previo al desarrollo. Es una decisión arquitectónica que condiciona rendimiento, costo, mantenibilidad, escalabilidad y hasta la facilidad con la que el equipo podrá evolucionar el producto.
En bases de datos relacionales, mucha gente aprende a modelar pensando primero en entidades, tablas, claves primarias, claves foráneas y normalización. Ese enfoque sigue siendo válido en el mundo SQL, pero en Firestore el punto de partida debe cambiar. Aquí no se diseña para responder joins arbitrarios sobre tablas altamente normalizadas. Se diseña para entregar documentos listos para ser consumidos por la aplicación, con el menor número posible de lecturas y con una estructura preparada para crecer.[cite:1][cite:2]
La documentación oficial de Firestore insiste en que al estructurar datos se puede elegir entre documentos anidados, subcolecciones o colecciones de nivel raíz, y que cada opción tiene ventajas y limitaciones según el caso de uso.[cite:2] Esa observación resume todo el corazón del modelado en Firestore: no existe una estructura única correcta para todos los problemas. Existe una estructura adecuada para un patrón de acceso concreto.
En este capítulo no se enseñarán aún consultas avanzadas ni reglas de seguridad. El foco estará en una habilidad más estratégica: aprender a pensar la base documental antes de codificar. Ese ejercicio es precisamente el que diferencia un prototipo funcional de una aplicación profesional preparada para escalar.
Desarrollo completo¶
¿Qué significa modelar datos?¶
Modelar datos significa traducir el dominio del negocio a una estructura persistente que la aplicación pueda leer y escribir de manera eficiente. En Firestore, eso implica decidir qué será una colección, qué será un documento, qué información vivirá junta, qué información estará duplicada deliberadamente y qué partes crecerán como subcolecciones.[cite:2]
Desde un punto de vista profesional, modelar datos no es “guardar cosas”. Es diseñar el camino más eficiente entre tres mundos: la realidad del negocio, la experiencia de usuario y las restricciones técnicas de la base de datos. Un mal modelo no solo es feo desde el punto de vista teórico; suele producir más lecturas, pantallas más lentas, reglas más complejas y costos más altos.
En Firestore, el modelado es todavía más importante porque el sistema es muy flexible. Esa flexibilidad es una ventaja enorme, pero también significa que la base no impondrá por sí sola un diseño ordenado. La responsabilidad de crear una estructura profesional recae en el arquitecto y en el equipo.
Diferencias entre modelado SQL y NoSQL¶
La primera diferencia fundamental es la unidad de diseño. En SQL, la unidad mental es la tabla y la relación entre tablas. En Firestore, la unidad mental es el documento y la forma en que ese documento será consumido por la aplicación.[cite:1][cite:2]
En SQL, es normal modelar primero la integridad relacional y luego reconstruir vistas funcionales mediante joins. En Firestore, la estrategia suele invertirse: primero se piensa qué necesita leer la interfaz o el flujo de negocio y después se decide qué documentos deben existir para responder a eso con el menor costo posible. Dicho de otro modo, Firestore premia el diseño orientado al acceso, no solo el diseño orientado a la pureza estructural.
Esto también afecta la normalización. En SQL, duplicar datos suele verse como un problema a evitar. En Firestore, cierta duplicación controlada puede ser una decisión correcta si reduce lecturas, elimina joins manuales y simplifica la experiencia de la aplicación.
Pensar en consultas antes que en tablas¶
Aunque este capítulo no entra todavía en consultas avanzadas, sí es imprescindible introducir la lógica de diseño que Firestore requiere: primero se piensa en cómo la aplicación leerá los datos. Esa es una recomendación práctica constante del ecosistema Firestore y está alineada con la manera en que la documentación orienta a elegir estructuras según el caso de uso.[cite:2]
Esto significa formular preguntas concretas antes de diseñar:
- ¿Qué necesita ver el usuario en esta pantalla?
- ¿Cuántos documentos hay que leer para renderizarla?
- ¿La información cambia en tiempo real o es estática?
- ¿La lista crecerá mucho con el tiempo?
- ¿Necesitamos leer el conjunto completo o solo una parte?
Si una respuesta frecuente es “la pantalla necesita combinar cinco entidades distintas para mostrar información básica”, probablemente el modelo documental aún no está bien resuelto. En Firestore, un buen diseño reduce fricción de lectura. No elimina toda relación entre entidades, pero intenta que la aplicación consuma la información con la menor cantidad de pasos posibles.
Diseñar para las lecturas¶
La razón por la que Firestore exige pensar en lecturas es doble: rendimiento y costo. Cada lectura consume tiempo, ancho de banda y facturación potencial. Un modelo que obliga a leer demasiados documentos para construir una vista simple suele ser peor tanto técnica como económicamente.
Por eso, diseñar para lecturas significa agrupar información que se consulta junta con frecuencia y separar aquella que crece de forma independiente o se usa solo en escenarios específicos. La guía oficial sobre estructuras de datos deja esto muy claro: los datos anidados son útiles para listas simples y fijas; las subcolecciones son mejores cuando la lista crecerá; las colecciones raíz son adecuadas para conjuntos dispares y relaciones de varios a varios.[cite:2]
Esta idea será central para el proyecto del libro. Por ejemplo, si una ficha de curso siempre muestra nombre del docente, título de institución y estado general, no tiene sentido que cada carga de pantalla dispare una cadena excesiva de lecturas si parte de esa información puede representarse de forma más directa.
Diseñar para la escalabilidad¶
Firestore está pensado para escalar automáticamente, pero la documentación técnica sobre lecturas y escrituras a escala advierte que el diseño sigue importando para mantener alto rendimiento y confiabilidad.[cite:3] En particular, recomienda comprender cómo se comportan lecturas y escrituras en el backend, mantener transacciones pequeñas y evitar hotspots distribuyendo operaciones a lo largo del rango de claves.[cite:3]
Esto significa que el modelado no puede quedarse en la semántica del negocio. También debe pensar en volumen y patrón de tráfico. Una colección puede tener millones de documentos sin problema, pero ciertas estrategias de ID, ciertas escrituras concentradas o ciertos documentos excesivamente calientes pueden perjudicar el rendimiento.[cite:3]
Diseñar para escalabilidad implica asumir que el modelo debe seguir funcionando cuando el sistema ya no tenga cien registros, sino millones. Y eso obliga a evitar estructuras que dependen demasiado de documentos monolíticos, contadores ultra concentrados o listas crecientes dentro de un solo documento.
Colecciones¶
Las colecciones son el primer nivel de organización lógica en Firestore. En modelado profesional, una colección debe agrupar entidades del mismo tipo funcional o técnico. La guía oficial muestra que las colecciones de nivel raíz son adecuadas para organizar conjuntos de datos dispares y para relaciones de varios a varios, aunque obtener datos naturalmente jerárquicos puede volverse más complejo si todo se lleva a raíz.[cite:2]
Por eso, la pregunta correcta no es solo “qué colección necesito”, sino “qué criterio de agrupación me ayuda a leer y administrar mejor estos datos”. Una colección usuarios tiene sentido porque todos sus documentos representan usuarios. Una colección cursos también. Pero no todo debe vivir siempre al mismo nivel si la naturaleza del dominio es claramente jerárquica.
Las colecciones también deben pensarse con vocación de crecimiento. Si una entidad puede alcanzar cientos de miles o millones de documentos, eso no es un problema en sí. El problema aparece cuando el diseño presupone que la colección siempre será pequeña y termina acoplando otras decisiones a esa suposición equivocada.
Documentos¶
Un documento debe representar una unidad de información coherente y útil para la aplicación. La documentación oficial del modelo de datos y la guía de estructura de datos coinciden en que Firestore funciona mejor con documentos pequeños, claros y fáciles de consultar.[cite:1][cite:2]
Un error clásico de principiantes es tratar el documento como si fuera una mini base entera: demasiados campos, listas crecientes, estados históricos, arrays enormes y estructuras anidadas que intentan evitar nuevas colecciones. Ese enfoque suele degradar el diseño. Un documento profesional contiene lo necesario para representar una entidad o un estado, no todo lo imaginable sobre ella.
Desde el punto de vista del proyecto del libro, un usuario, un curso, una tarea o una notificación son buenos candidatos a documentos. Un historial masivo de acciones o una colección creciente de evidencias no lo son tanto si se intenta incrustarlos dentro del documento principal.
Subcolecciones¶
La guía oficial recomienda subcolecciones cuando los datos pueden expandirse con el tiempo, porque así el documento principal no crece, se mantienen capacidades de consulta completas y además se pueden hacer consultas de grupo sobre subcolecciones.[cite:2] Esa recomendación es una de las más importantes para modelado en Firestore.
La subcolección es una herramienta poderosa cuando existe una relación jerárquica fuerte. Por ejemplo, una clase puede tener materiales, una tarea puede tener entregas o una conversación puede tener mensajes. En estos casos, almacenar todo dentro del documento principal sería poco escalable y dificultaría las consultas.
Sin embargo, la documentación también advierte una limitación práctica: no es tan fácil borrar subcolecciones enteras.[cite:2] Eso obliga a pensar en mantenimiento y ciclos de vida. No basta con que una subcolección “se vea bonita” jerárquicamente; también hay que considerar cómo se administrará con el tiempo.
Campos simples¶
Los campos simples son la forma más barata y directa de representar atributos básicos: nombre, estado, fecha, rol, tipo, activo, visibilidad, etcétera. Siempre que un dato sea atómico y se lea con frecuencia junto al resto del documento, suele tener sentido como campo simple.
El valor de los campos simples está en la claridad. Hacen que el documento sea fácil de comprender, fácil de proyectar mentalmente y fácil de consumir por la app. Además, suelen ser mejores candidatos para ordenar, filtrar o mostrar rápidamente en listados futuros.
En modelado profesional, la regla práctica es no complicar lo que puede ser simple. Si un valor se puede expresar como campo plano sin perder semántica, eso suele ser mejor que encapsularlo en estructuras complejas innecesarias.
Campos compuestos¶
Los campos compuestos, entendidos como objetos o mapas con varios atributos relacionados, son útiles cuando ciertos datos forman una unidad lógica inseparable dentro del documento. La guía oficial habla de objetos complejos anidados como arrays o mapas dentro de documentos y reconoce que esta opción es fácil de configurar y optimiza la estructura cuando se trata de listas simples o datos estables.[cite:2]
Por ejemplo, una dirección, una configuración de notificación o una preferencia visual puede tener sentido como objeto anidado. Pero aquí aparece una advertencia importante: si ese objeto empieza a crecer demasiado, a cambiar frecuentemente por separado o a necesitar consultas propias, quizá debería convertirse en otra estructura.
La clave está en la cohesión. Un campo compuesto es correcto cuando sus partes viven y se consumen juntas. Si no, probablemente solo está escondiendo una necesidad de modelado más explícita.
Arrays¶
Los arrays son cómodos, pero deben usarse con criterio. La guía oficial reconoce que una lista simple y fija dentro del documento puede ser razonable, como las tres salas visitadas recientemente por un usuario en una app de chat.[cite:2] El mensaje implícito es muy importante: arrays pequeños y controlados, sí; listas grandes y crecientes dentro del documento, no.
El problema de un array no es solo su tamaño. También es su evolución. Cuando un array crece indefinidamente, el documento completo crece con él y puede hacerse más lento de recuperar.[cite:2] Además, un array masivo dentro de una entidad central suele indicar que la información necesita otra forma de modelado.
Por eso, en el proyecto del libro, un array puede servir para etiquetas, permisos resumidos o preferencias pequeñas. No debería usarse para listas de clases completas, evidencias acumuladas o notificaciones históricas de gran volumen.
Objetos anidados¶
Los objetos anidados comparten varias ventajas y límites con los arrays. Son útiles para mantener juntas pequeñas estructuras relacionadas dentro del documento, como configuraciones, metadatos compactos o bloques secundarios de información.[cite:2]
Su mayor ventaja es que simplifican la recuperación del documento. La app obtiene un solo objeto bien estructurado, listo para usar. Su mayor riesgo es que el documento se convierta en un contenedor excesivamente complejo, difícil de mantener y lento de leer si la anidación crece sin control.
Como regla general, un objeto anidado debe existir para simplificar, no para aplazar una decisión de diseño. Si se convierte en una mini base de datos dentro del documento, ya dejó de cumplir su función.
Referencias entre documentos¶
Las referencias permiten conectar entidades sin convertir Firestore en una base relacional clásica. Son útiles cuando una entidad necesita apuntar a otra, pero no necesariamente incorporar toda su información. Un curso puede referenciar al docente creador; una tarea puede referenciar la clase; una evidencia puede referenciar al alumno y a la entrega.
Desde el punto de vista del modelado, una referencia ayuda a preservar separación entre entidades cuando esa separación tiene valor funcional. Pero también obliga a pensar el costo de navegación. Si para pintar una pantalla se necesitan demasiadas referencias y lecturas consecutivas, quizá el diseño necesita incorporar duplicación selectiva.
El criterio profesional no es elegir entre “todo referenciado” o “todo duplicado”. Es equilibrar dependencia, claridad y eficiencia de lectura según el flujo real de la aplicación.
IDs automáticos vs IDs personalizados¶
Firestore permite usar IDs generados automáticamente o IDs definidos por la aplicación.[cite:1] La elección no es trivial, porque afecta legibilidad, distribución de escrituras, interoperabilidad y mantenimiento.
Los IDs automáticos suelen ser excelentes para entidades donde solo importa unicidad y buena distribución. Además, ayudan a evitar concentraciones problemáticas si el sistema genera muchísimos documentos, ya que la documentación sobre escalado enfatiza la importancia de distribuir operaciones a lo largo del espacio de claves y evitar hotspots.[cite:3]
Los IDs personalizados son útiles cuando existe una identidad natural estable, como el UID de Authentication para un usuario o un identificador institucional controlado. Aun así, conviene no abusar de claves semánticas largas o demasiado mutables. Un ID debe identificar, no volverse un resumen del negocio.
Normalización¶
La normalización, en sentido clásico, busca reducir duplicación y mantener una sola fuente de verdad para cada dato. Este principio sigue siendo útil en Firestore, pero no puede aplicarse de forma dogmática. Si se lleva demasiado lejos, el resultado es un modelo que obliga a encadenar lecturas para recomponer información muy básica.
Hay ámbitos del modelo donde conviene conservar una normalización fuerte: entidades maestras, perfiles extensos, configuraciones críticas o catálogos institucionales. En esos casos, tener una fuente central clara puede facilitar mantenimiento y evitar inconsistencias.
Sin embargo, Firestore no recompensa automáticamente la pureza normalizada. Si esa pureza daña el rendimiento o multiplica costos, deja de ser una virtud práctica y se convierte en un problema.
Desnormalización¶
La desnormalización en Firestore no es un parche ni una mala práctica automática. Es una técnica legítima y muy frecuente para adaptar el modelo a las lecturas reales. Consiste en duplicar o resumir cierta información en varios documentos para reducir dependencias y evitar lecturas adicionales.
La clave es que esa duplicación sea intencional y controlada. No se duplica todo, solo lo que mejora significativamente la eficiencia del sistema. Un ejemplo común sería guardar en un documento de curso un resumen del docente: nombre público y avatar, en lugar de obligar a consultar siempre el perfil completo del docente para listados sencillos.
La desnormalización correcta reduce complejidad del cliente. La desnormalización indiscriminada crea inconsistencias. El mérito profesional está en saber distinguir ambas.
Duplicación de información¶
La duplicación de información en Firestore debe evaluarse con tres preguntas:
- ¿Reduce lecturas frecuentes?
- ¿Simplifica la interfaz o el flujo de negocio?
- ¿La eventual sincronización de ese dato duplicado es aceptable?
Si la respuesta a las dos primeras es sí y la tercera también es manejable, duplicar puede ser correcto. Por ejemplo, en una lista de tareas puede tener sentido mostrar el nombre del curso y del docente sin necesidad de navegar por varias referencias cada vez.
Si, en cambio, el dato cambia constantemente o la inconsistencia sería muy costosa, quizá convenga mantener una única fuente y asumir la lectura extra en ciertos contextos. La decisión nunca debe basarse solo en comodidad del modelador.
¿Cuándo duplicar datos?¶
Conviene duplicar cuando el sistema necesita mostrar datos juntos de manera muy frecuente, cuando el costo de no duplicarlos es alto en lecturas o latencia, y cuando el dato duplicado es relativamente estable o fácil de sincronizar.
No conviene duplicar cuando el dato es muy volátil, cuando la consistencia estricta entre copias es crítica o cuando la duplicación no produce ningún beneficio de acceso real. En otras palabras, duplicar por costumbre es tan malo como no duplicar nunca.
Un buen principio práctico es duplicar resúmenes, no necesariamente entidades completas. Nombre visible, rol visible, estado, miniatura, título corto o identificadores secundarios suelen ser buenos candidatos. Perfiles enteros, historiales complejos o configuraciones densas suelen no serlo.
Relaciones uno a uno¶
Las relaciones uno a uno en Firestore pueden resolverse de varias maneras. Si ambos conjuntos de datos siempre se leen juntos y no crecerán mucho, puede tener sentido que vivan en el mismo documento. Si su ciclo de vida o patrón de acceso es distinto, puede ser mejor separarlos y usar referencias.
Por ejemplo, un perfil extendido de usuario puede vivir en el mismo documento si la app siempre lo necesita. Pero si hay un bloque administrativo pesado o un conjunto de preferencias poco utilizadas, quizás convenga otra estructura para no cargar innecesariamente el documento principal.
La regla general es evaluar cohesión y frecuencia de acceso. Uno a uno no significa automáticamente “todo junto” ni automáticamente “todo separado”.
Relaciones uno a muchos¶
Las relaciones uno a muchos son quizá las más importantes en Firestore. La decisión clave es si el “muchos” cabe razonablemente dentro del documento o si debe convertirse en subcolección o colección independiente. La guía oficial es clara: si el conjunto puede expandirse, suele ser mejor una subcolección; si la relación es más transversal o varios a varios, las colecciones de raíz pueden ser más adecuadas.[cite:2]
Un curso con miles de tareas no debe guardar todas esas tareas en un array. Una clase con cientos de evidencias tampoco debe incrustarlas en un solo documento. En estos casos, la solución profesional suele ser subcolección o colección especializada.
Aquí se ve con fuerza el principio de escalabilidad: un modelo correcto para diez elementos puede ser pésimo para diez mil.
Relaciones muchos a muchos¶
En Firestore, las relaciones muchos a muchos normalmente se resuelven mejor con colecciones independientes o estructuras puente explícitas. La propia guía de estructura señala que las colecciones raíz son buenas para relaciones de varios a varios.[cite:2]
Por ejemplo, alumnos y cursos pueden necesitar una relación muchos a muchos. En lugar de guardar arrays gigantescos de cursos dentro del alumno y arrays gigantescos de alumnos dentro del curso, suele ser más profesional introducir una colección intermedia de inscripciones, membresías o participaciones.
Esta solución ofrece varias ventajas: hace explícita la relación, permite añadir metadatos a la vinculación y evita documentos crecientes y poco escalables. Además, facilita consultas futuras sobre el estado de la inscripción, fechas, roles u observaciones.
Modelado jerárquico¶
El modelado jerárquico usa documentos y subcolecciones para representar estructuras naturalmente contenidas. Es muy útil cuando el dominio realmente tiene una relación padre-hijo clara: institución → grupos, curso → clases, clase → tareas, tarea → entregas.
Su principal ventaja es la claridad contextual. Ver una subcolección dentro de un documento hace evidente quién es el propietario lógico del conjunto. También ayuda a mantener compacto el documento principal mientras el conjunto hijo crece.[cite:2]
Su principal límite es que no todo debe convertirse en jerarquía. Cuando una entidad necesita ser consultada transversalmente desde muchos lugares o participa en relaciones más complejas, a veces conviene que exista como colección propia.
Modelado por colecciones independientes¶
El modelado por colecciones independientes es especialmente útil para entidades centrales del negocio que existen por sí mismas y se consultan desde múltiples contextos: usuarios, cursos, instituciones, archivos, notificaciones o inscripciones.
La guía oficial indica que las colecciones de nivel raíz son adecuadas para organizar conjuntos de datos dispares y relaciones muchos a muchos, aunque los datos naturalmente jerárquicos pueden hacerse más difíciles de reconstruir si todo vive ahí.[cite:2] Esa observación debe guiar la decisión: usar raíz cuando gana flexibilidad transversal; usar jerarquía cuando gana contexto.
En aplicaciones profesionales, suele aparecer una combinación de ambas estrategias. El buen modelado en Firestore rara vez es puramente jerárquico o puramente plano.
Modelado para aplicaciones en tiempo real¶
Cuando una aplicación necesita tiempo real, el modelo debe evitar lecturas excesivas, documentos sobredimensionados y flujos que obliguen a escuchar demasiadas piezas al mismo tiempo. Firestore soporta sincronización en tiempo real, pero eso no significa que todo deba estar suscrito siempre.[cite:1]
Un patrón profesional es reservar tiempo real para aquello que realmente cambia frecuentemente y cuya actualización inmediata aporta valor a la experiencia: estado de entregas, notificaciones, cambios de presencia, mensajes, actualizaciones de tareas o progreso de clase. Para datos estables, una lectura puntual puede ser suficiente.
Modelar para tiempo real significa reducir la superficie reactiva del sistema. Escuchar menos, pero escuchar mejor.
Modelado orientado a costos¶
El costo en Firestore está profundamente conectado con las lecturas, escrituras y el tamaño de los documentos. Por eso, el modelado orientado a costos busca minimizar lecturas redundantes, evitar relecturas de documentos grandes y reducir patrones donde una simple pantalla dispare múltiples accesos innecesarios.
En la práctica, esto significa:
- Duplicar resúmenes donde realmente reduzcan lecturas.
- Evitar arrays o documentos gigantes que obliguen a transferir demasiado contenido.
- Separar datos fríos de datos calientes.
- No obligar a navegar múltiples referencias para vistas básicas.
- Diseñar listados compactos y detalles completos como documentos distintos si hace falta.
La mejor optimización económica en Firestore suele empezar en el modelo, no en una supuesta “técnica mágica” posterior.
Modelado orientado al rendimiento¶
La documentación sobre escalado insiste en que para mantener alto rendimiento deben distribuirse operaciones a lo largo del rango de claves, evitar hotspots y mantener pequeñas las transacciones.[cite:3] Esas recomendaciones tienen efecto directo sobre el modelado.
Un modelo orientado al rendimiento evita concentrar demasiadas escrituras en un mismo documento, evita estructuras donde muchas operaciones recaen siempre sobre la misma clave y reduce la necesidad de transacciones grandes. También intenta que los documentos críticos sean pequeños y fáciles de acceder.
Rendimiento en Firestore no significa solo “consultas rápidas”. También significa mantener saludable el backend cuando el volumen y el tráfico crecen con el tiempo.[cite:3]
Patrones recomendados por Google¶
A partir de la documentación oficial, pueden extraerse varios patrones muy valiosos:
- Usar datos anidados solo para listas simples y fijas.[cite:2]
- Elegir subcolecciones cuando los datos crecerán y se necesitan consultas completas sobre ellos.[cite:2]
- Usar colecciones raíz para conjuntos dispares y relaciones muchos a muchos.[cite:2]
- Mantener documentos pequeños.[cite:2]
- Evitar hotspots distribuyendo operaciones y evitando concentración sobre un rango estrecho de claves.[cite:3]
- Mantener transacciones pequeñas.[cite:3]
- Diseñar entendiendo cómo trabajan internamente las lecturas y escrituras a escala.[cite:3]
Estos patrones no son recetas rígidas, pero sí constituyen una base excelente para decisiones profesionales.
Anti patrones frecuentes¶
Hay varios anti patrones muy comunes en Firestore:
- Usar un documento como si fuera una tabla entera.
- Guardar listas crecientes enormes dentro de arrays en un solo documento.[cite:2]
- Reproducir relaciones relacionales con demasiadas referencias y lecturas encadenadas.
- Duplicar información sin criterio ni estrategia de actualización.
- No duplicar nunca por purismo, aun cuando eso multiplica lecturas.
- Crear IDs secuenciales o patrones de escritura que concentren demasiado tráfico, favoreciendo hotspots.[cite:3]
- Diseñar jerarquías profundas solo porque “se ven organizadas”, aunque luego dificulten consultas transversales.
Un anti patrón no es simplemente una mala práctica estética. En Firestore suele transformarse rápidamente en lentitud, complejidad o factura innecesaria.
Errores comunes al diseñar Firestore¶
Entre los errores más frecuentes están estos:
- Pensar primero en tablas en lugar de pensar en pantallas y flujos.
- Modelar la base para que “se parezca” a SQL aunque el acceso resultante sea ineficiente.
- Usar arrays para conjuntos que crecerán sin límite.[cite:2]
- Elegir subcolecciones cuando en realidad se necesitan consultas transversales más propias de colecciones independientes.[cite:2]
- Usar referencias en todos lados y descubrir demasiado tarde que una vista simple necesita demasiadas lecturas.
- Duplicar información crítica sin una estrategia clara de sincronización.
- No pensar desde el principio en volumen, costos y rendimiento.[cite:3]
Buenas prácticas profesionales¶
Un diseño profesional en Firestore suele seguir estos principios:
- Comenzar por los casos de uso y flujos principales, no por una lista abstracta de entidades.
- Diseñar para las lecturas más frecuentes.
- Aceptar cierta desnormalización cuando mejora significativamente rendimiento y costos.
- Mantener una fuente de verdad clara para los datos más sensibles.
- Separar datos que crecen mucho en subcolecciones o colecciones independientes.
- Evitar documentos gigantes y escrituras calientes recurrentes sobre la misma clave.[cite:2][cite:3]
- Pensar el modelo para el millón de documentos, no solo para la demo de mañana.
- Documentar convenciones de nombres, IDs, campos y duplicación.
Comparaciones técnicas¶
SQL vs Firestore en modelado¶
| Tema | SQL | Firestore |
|---|---|---|
| Punto de partida | Tablas y relaciones | Consultas y patrones de acceso |
| Estrategia típica | Normalización | Mezcla de normalización y desnormalización |
| Relaciones muchos a muchos | Tabla puente | Colección puente o colección independiente |
| Jerarquía | Se resuelve por joins | Se expresa con subcolecciones y documentos |
| Optimización habitual | Índices y joins eficientes | Menos lecturas, documentos pequeños, evitar hotspots |
La enseñanza aquí es clara: Firestore no elimina el modelado, lo obliga a cambiar de foco.
Documento anidado vs subcolección vs colección raíz¶
| Opción | Cuándo conviene | Riesgo principal |
|---|---|---|
| Datos anidados | Listas pequeñas, estables, consumidas junto al documento.[cite:2] | Escala mal si el conjunto crece.[cite:2] |
| Subcolección | Datos jerárquicos que crecerán y requieren consultas propias.[cite:2] | Complejidad de borrado y menor transversalidad.[cite:2] |
| Colección raíz | Entidades independientes o relaciones muchos a muchos.[cite:2] | Reconstruir jerarquías puede requerir más lógica.[cite:2] |
Casos prácticos¶
Caso 1: perfil de usuario¶
Alternativa A: guardar todo el perfil, configuraciones, actividad reciente y notificaciones en un solo documento.
Problema: el documento crece demasiado, mezcla datos fríos y calientes y cada lectura trae información innecesaria.
Alternativa B: mantener un documento principal de usuario con identidad y metadatos esenciales, y separar actividad reciente y notificaciones en otras estructuras.
Recomendación: la alternativa B es más profesional porque el perfil principal sigue siendo ligero y la app solo lee lo necesario en cada flujo.[cite:2]
Caso 2: curso con clases y tareas¶
Alternativa A: guardar clases y tareas como arrays dentro del documento del curso.
Problema: a medida que el curso crece, el documento se vuelve grande y cada lectura del curso arrastra información que no siempre se necesita.[cite:2]
Alternativa B: el curso vive como documento y sus clases o tareas se modelan como subcolecciones o colecciones separadas según el patrón de acceso.
Recomendación: la alternativa B es claramente mejor para escalabilidad y mantenimiento.[cite:2]
Caso 3: alumnos inscritos en cursos¶
Alternativa A: un array de miles de alumnos dentro del curso y un array de miles de cursos dentro del alumno.
Problema: duplicación masiva, crecimiento sin control y mantenimiento difícil.
Alternativa B: colección independiente de inscripciones con metadatos de la relación.
Recomendación: la alternativa B es más profesional porque modela explícitamente el muchos a muchos y permite consultar la relación como entidad de negocio.
Diseño del modelo de datos del proyecto¶
A continuación se propone un diseño profesional inicial para el proyecto oficial del libro. No es la única opción posible, pero sí una opción equilibrada para rendimiento, crecimiento y claridad operativa.
Principios de diseño del proyecto¶
Antes de definir colecciones, se fijan estos principios:
- Los documentos principales deben ser pequeños y representativos.
- Las entidades centrales del dominio vivirán en colecciones raíz.
- Las relaciones muchos a muchos se modelarán con colecciones puente.
- Los datos que crezcan mucho o tengan ciclo de vida propio no se incrustarán en arrays largos.
- Se duplicarán resúmenes donde eso reduzca lecturas en vistas frecuentes.
- Se evitarán escrituras excesivamente concentradas en un único documento.[cite:3]
1. Usuarios¶
Colección raíz: usuarios
Cada usuario tendrá un documento identificado preferentemente por el UID de Authentication. Esta decisión es recomendable porque existe una identidad natural estable y simplifica el cruce entre autenticación y base de datos.
Contenido sugerido del documento:
- Datos esenciales de cuenta.
- Estado general.
- Rol principal visible.
- Resumen de perfil.
- Metadatos de creación y actualización.
Justificación: el usuario es una entidad central y transversal. Debe poder consultarse desde muchas partes del sistema sin depender de una jerarquía específica.
2. Perfiles¶
Hay dos alternativas principales:
- Incluir perfil básico dentro del documento
usuarios. - Crear una colección separada
perfileso un subdocumento pesado.
Recomendación: mantener el perfil básico dentro de usuarios y reservar una estructura separada solo si el perfil se vuelve significativamente más grande o especializado.
Justificación: en la mayoría de pantallas, identidad y perfil básico se leen juntos. Separarlos demasiado pronto agregaría lecturas innecesarias.
3. Roles¶
Los roles pueden resolverse como campo simple o como colección maestra, dependiendo de la complejidad.
Recomendación:
- En el usuario, guardar el rol actual como campo simple resumido.
- Si existen metadatos complejos de rol, usar una colección maestra
roles.
Justificación: la aplicación necesita saber rápidamente el rol del usuario sin hacer consultas adicionales, pero el catálogo formal de roles puede merecer centralización si crece.
4. Instituciones¶
Colección raíz: instituciones
Las instituciones son entidades independientes: escuelas, centros de formación o academias. Se consultan transversalmente y participan en muchas relaciones.
Justificación: son maestras del dominio y no deben depender jerárquicamente de un usuario individual o de un curso concreto.
5. Docentes¶
Existen dos alternativas:
- Colección separada
docentes. - Usar
usuarioscon un rol docente y un perfil específico ampliado.
Recomendación: usar usuarios como entidad base y complementar con una colección docentes solo para atributos específicos del rol docente si estos son numerosos o especializados.
Justificación: así se evita duplicar toda la identidad del usuario y se mantiene una separación limpia entre cuenta general y perfil profesional especializado.
6. Alumnos¶
La misma lógica aplica aquí.
Recomendación: usar usuarios como entidad base y una colección alumnos para atributos académicos específicos solo cuando hagan falta.
Justificación: muchos sistemas educativos comparten identidad base entre distintos roles; separar completamente desde el inicio suele generar redundancia innecesaria.
7. Grupos¶
Colección raíz: grupos
Los grupos representan conjuntos organizativos de alumnos o cursos. Deben consultarse desde diferentes contextos y probablemente necesiten relación con institución, docentes y alumnos.
Justificación: son entidades transversales. Guardarlas como subcolecciones de instituciones podría parecer lógico, pero dificultaría algunas consultas cruzadas si el sistema crece. Es más profesional mantenerlas independientes con referencias o resúmenes.
8. Cursos¶
Colección raíz: cursos
Cada curso será una entidad central y debe existir como documento propio. El documento incluirá información esencial del curso y resúmenes útiles como nombre del docente principal o de la institución si eso reduce lecturas frecuentes.
Justificación: un curso será consultado por listados, detalles, dashboards, tareas y clases. Debe ser accesible de manera directa.
9. Clases¶
Aquí hay dos alternativas fuertes:
- Subcolección
clasesdentro de cadacurso. - Colección raíz
clasescon referencia al curso.
Recomendación: usar subcolección clases dentro de cursos/{cursoId} cuando la navegación principal sea claramente dependiente del curso; evaluar colección raíz adicional solo si se requieren consultas transversales masivas sobre clases en todo el sistema.
Justificación: la relación curso → clases es naturalmente jerárquica y encaja bien con subcolección.[cite:2]
10. Tareas¶
También hay varias opciones:
- Subcolección dentro de
clases. - Colección independiente
tareascon referencia a clase y curso.
Recomendación: si la tarea siempre se consulta dentro del contexto de una clase, puede vivir como subcolección. Si tendrá listados globales por alumno, docente o institución, una colección raíz puede ser más profesional.
Decisión recomendada para el proyecto: tareas como colección raíz con referencias a curso y clase, manteniendo resúmenes clave duplicados.
Justificación: esto facilita dashboards, búsquedas y paneles globales sin depender demasiado de jerarquías profundas.
11. Evidencias¶
Las evidencias son entregas, archivos o pruebas relacionadas con tareas y alumnos. Tienen alto potencial de crecimiento.
Recomendación: colección raíz evidencias con referencias a tareaId, alumnoId, cursoId y quizá claseId, más resúmenes visibles.
Justificación: las evidencias suelen necesitar consultas por alumno, por tarea, por curso y por estado. Modelarlas solo como subcolección de la tarea limitaría la flexibilidad transversal.
12. Archivos¶
Los archivos físicos vivirán en Cloud Storage, pero Firestore necesitará almacenar metadatos.
Recomendación: colección archivos independiente para metadatos comunes y referencias desde otras entidades cuando sea necesario.
Justificación: separar metadatos de archivos evita duplicación excesiva y permite reutilización entre tareas, evidencias, credenciales o perfiles.
13. Notificaciones¶
Colección recomendada: notificaciones
Aquí hay dos modelos posibles:
- Subcolección por usuario:
usuarios/{uid}/notificaciones - Colección raíz
notificacionesconuserId
Recomendación: para una aplicación centrada en usuario y consultas por destinatario, la subcolección por usuario puede ser muy natural. Pero si se necesitan paneles administrativos globales, una colección raíz podría ser mejor.
Decisión recomendada para el proyecto: subcolección por usuario para consumo personal y simplicidad contextual; considerar procesos auxiliares si más adelante se necesita analítica global.
Justificación: la mayoría de las lecturas de notificaciones son por usuario autenticado, así que la jerarquía favorece el acceso cotidiano.
14. Configuraciones¶
Las configuraciones pueden dividirse en dos niveles:
- Configuración global del sistema: colección
configuracionesSistema - Configuración personal del usuario: objeto anidado o subdocumento en
usuarios
Recomendación: mantener configuraciones personales básicas dentro del usuario y configuraciones de sistema en colección independiente.
Justificación: se optimizan lecturas frecuentes del perfil y se separan las preferencias globales del dominio administrativo.
Relaciones clave del proyecto¶
El modelo propuesto puede resumirse así:
usuarioscomo identidad base.instituciones,grupos,cursos,tareas,evidencias,archivoscomo colecciones raíz.cursos/{cursoId}/clasescomo subcolección jerárquica.usuarios/{uid}/notificacionescomo subcolección centrada en el usuario.- Colecciones auxiliares
docentes,alumnosorolessolo si la especialización del dominio lo justifica.
Alternativas comparadas¶
| Entidad | Alternativa 1 | Alternativa 2 | Recomendación |
|---|---|---|---|
| Docente / Alumno | Colecciones separadas completas | Usuario base + perfil especializado | Usuario base + especialización |
| Clases | Colección raíz | Subcolección de curso | Subcolección de curso |
| Tareas | Subcolección de clase | Colección raíz | Colección raíz |
| Evidencias | Subcolección de tarea | Colección raíz | Colección raíz |
| Notificaciones | Colección raíz global | Subcolección por usuario | Subcolección por usuario |
Razones de la recomendación general¶
El modelo recomendado busca equilibrio entre jerarquía y transversalidad. Se usa subcolección cuando la relación padre-hijo es fuerte y la lectura principal ocurre en ese contexto. Se usa colección raíz cuando la entidad necesita consultas desde múltiples puntos del sistema. Y se aplica duplicación selectiva de resúmenes para reducir lecturas costosas en pantallas frecuentes.
Buenas prácticas¶
- Diseñar a partir de pantallas, flujos y casos de uso.
- Mantener documentos pequeños y bien cohesionados.[cite:2]
- Usar subcolecciones para conjuntos crecientes y jerárquicos.[cite:2]
- Usar colecciones raíz para entidades transversales y relaciones complejas.[cite:2]
- Duplicar solo resúmenes útiles.
- Elegir IDs personalizados solo cuando exista una identidad natural estable.
- Preferir IDs automáticos cuando se busque unicidad y buena distribución de escrituras.[cite:3]
- Evitar hotspots distribuyendo operaciones y no concentrando carga sobre una clave única.[cite:3]
- Documentar convenciones de modelado antes de implementar.
- Revisar periódicamente el modelo conforme crece el producto.
Errores comunes¶
- Copiar directamente el esquema relacional al mundo Firestore.
- Diseñar primero la base y después pensar cómo la app leerá los datos.
- Usar arrays para datos de crecimiento indefinido.[cite:2]
- Crear documentos gigantes por miedo a duplicar información.
- Duplicar demasiados datos sin plan de actualización.
- Elegir subcolecciones donde se necesitan consultas globales.
- Usar colecciones raíz para todo aunque el dominio sea claramente jerárquico.
- No pensar en costos ni rendimiento al definir el modelo.
- No anticipar el volumen de escritura y los hotspots posibles.[cite:3]
Resumen¶
Modelar datos en Cloud Firestore exige cambiar de mentalidad. Ya no se trata de traducir el negocio a tablas altamente normalizadas, sino de diseñar documentos, subcolecciones y colecciones independientes en función de cómo la aplicación leerá y escribirá la información.[cite:1][cite:2]
Un modelo profesional en Firestore equilibra normalización y desnormalización, usa jerarquía cuando aporta contexto, colecciones raíz cuando aporta transversalidad, y duplicación selectiva cuando reduce lecturas, costo y complejidad. También piensa desde el inicio en escalabilidad, evitando documentos grandes, listas crecientes y patrones de escritura calientes.[cite:2][cite:3]
Para el proyecto del libro, la arquitectura recomendada combina usuarios como entidad base, colecciones centrales para instituciones, cursos, tareas, evidencias y archivos, subcolecciones para clases y notificaciones, y estructuras puente o especializadas cuando el dominio lo exige. Esa combinación permite crecer de forma ordenada, eficiente y coherente con las mejores prácticas documentales.
Conceptos clave¶
- Modelado documental.
- Diseñar para las lecturas.
- Diseñar para la escalabilidad.[cite:3]
- Colecciones raíz.[cite:2]
- Documentos pequeños.[cite:2]
- Subcolecciones.[cite:2]
- Datos anidados.[cite:2]
- Arrays controlados.[cite:2]
- Referencias entre documentos.
- IDs automáticos vs personalizados.
- Normalización.
- Desnormalización.
- Duplicación selectiva.
- Relaciones uno a uno.
- Relaciones uno a muchos.
- Relaciones muchos a muchos.
- Hotspots.[cite:3]
- Modelo orientado a costos.
Preguntas de repaso¶
- ¿Qué significa modelar datos en Firestore y por qué no equivale a diseñar tablas?[cite:1][cite:2]
- ¿Por qué en Firestore conviene pensar primero en lecturas y flujos de acceso?
- ¿Cuándo conviene usar datos anidados dentro de un documento?[cite:2]
- ¿Qué ventajas ofrecen las subcolecciones frente a arrays crecientes?[cite:2]
- ¿Cuándo es preferible una colección raíz en lugar de una jerarquía de subcolecciones?[cite:2]
- ¿Qué riesgos tiene una normalización excesiva en Firestore?
- ¿Cuándo es razonable duplicar datos y cuándo no?
- ¿Cómo modelarías una relación muchos a muchos entre alumnos y cursos?
- ¿Por qué los hotspots afectan el rendimiento y cómo puede influir el modelado en ellos?[cite:3]
- ¿Qué decisiones del modelo recomendado para el proyecto del libro ayudan más a reducir lecturas y facilitar escalabilidad?
Ejercicios prácticos¶
- Elige tres pantallas del proyecto del libro y describe qué documentos necesitarían para cargarse eficientemente.
- Diseña dos alternativas para almacenar
cursos,clasesytareas; compara sus ventajas y desventajas. - Propón un modelo para la relación entre
alumnosygruposjustificando si usarías colección puente, subcolección o arrays. - Toma una entidad como
usuarioy decide qué campos irían en el documento principal, cuáles serían objetos anidados y cuáles deberían vivir en otra estructura. - Diseña un caso donde duplicarías datos de un docente dentro de un curso y explica por qué esa duplicación sería aceptable.
- Analiza un anti patrón de Firestore que hayas visto o imaginado y rediseñalo siguiendo los criterios del capítulo.
Bibliografía y referencias oficiales¶
- Modelo de datos de Cloud Firestore: https://firebase.google.com/docs/firestore/data-model [cite:1]
- Guía oficial para elegir una estructura de datos en Firestore: https://firebase.google.com/docs/firestore/manage-data/structure-data [cite:2]
- Comprender lecturas, escrituras y escalado en Firestore: https://firebase.google.com/docs/firestore/understand-reads-writes-scale [cite:3]