Capítulo 12 — Índices, rendimiento y optimización en Cloud Firestore¶
Recursos visuales propuestos¶
Antes de desarrollar este capítulo conviene seleccionar únicamente los recursos visuales que realmente ayuden a entender cómo Firestore resuelve consultas y por qué la indexación determina el rendimiento. En esta temática, muchas ideas introductorias se comprenden mejor con comparaciones visuales sencillas, mientras que el comportamiento interno del motor de indexación exige diagramas más técnicos y editables.
Imágenes didácticas¶
- Comparación entre consulta indexada y no indexada. Se recomienda como imagen didáctica porque facilita explicar la diferencia entre una consulta resuelta rápidamente por una estructura preparada y otra que requiere un recorrido ineficiente o directamente no es admitida por el motor de Firestore.[cite:1][cite:2]
- Ejemplo de creación automática de un índice. Conviene como imagen didáctica porque el lector necesita reconocer visualmente el error de consulta y el flujo de creación desde la consola sin entrar todavía en detalles de arquitectura interna.[cite:2]
- Panel de administración de índices. Es mejor como imagen didáctica porque el objetivo pedagógico es ubicar visualmente la sección de índices, sus estados y su administración diaria dentro de Firebase Console.[cite:2]
- Relación entre consulta e índice. Funciona bien como imagen didáctica cuando se quiere mostrar que una consulta concreta necesita una estructura concreta.
- Representación visual del almacenamiento de índices. Puede presentarse como imagen didáctica porque ayuda a transmitir la idea de que indexar no es gratis: cada índice ocupa almacenamiento y aumenta trabajo de escritura.[cite:1][cite:3]
Diagramas SVG¶
- Funcionamiento interno del motor de indexación. Debe ser SVG porque requiere mostrar pasos internos, relaciones entre documentos, entradas de índice, ordenamientos y resolución de consulta con precisión técnica.[cite:2][cite:3]
- Flujo completo de ejecución de una consulta utilizando índices. Conviene SVG porque intervienen cliente, SDK, consulta, índice y recuperación de documentos.
- Arquitectura de índices compuestos. Se recomienda SVG porque implica representar varios campos, direcciones de ordenamiento y alcances de consulta de manera estructurada.[cite:2][cite:4]
- Relación entre consultas, índices y almacenamiento interno. También debe ser SVG porque es una vista arquitectónica que explica rendimiento, almacenamiento y costo de forma conectada.[cite:1][cite:3]
Objetivos de aprendizaje¶
Al finalizar este capítulo, el lector será capaz de:
- Comprender qué es un índice y por qué Firestore exige un índice para cada consulta.[cite:2]
- Diferenciar claramente entre indexación automática, índices simples, índices compuestos e índices para Collection Group.
- Interpretar errores de consultas que requieren índices y crear la estructura adecuada desde Firebase Console o Firebase CLI.[cite:2]
- Administrar los índices del proyecto mediante el archivo
firestore.indexes.jsony su despliegue controlado.[cite:2][cite:4] - Relacionar indexación con latencia, escalabilidad, almacenamiento, costos de escritura y costo de lectura.[cite:1][cite:3]
- Optimizar consultas del proyecto transversal del libro para reducir lecturas, fanout de índices y tiempos de respuesta.[cite:1][cite:3]
Introducción¶
En Firestore, las consultas rápidas no ocurren por casualidad. Ocurren porque el sistema mantiene estructuras auxiliares llamadas índices, diseñadas para localizar datos en el orden y con los filtros que la aplicación necesita. La propia documentación oficial lo expresa con claridad: Cloud Firestore asegura el rendimiento de las consultas al requerir un índice para cada consulta, y los índices necesarios para las búsquedas más básicas se crean automáticamente.[cite:2]
Este enfoque tiene una consecuencia arquitectónica profunda. En una base de datos relacional tradicional, muchas consultas pueden ejecutarse incluso sin un índice, aunque con degradación de rendimiento. En Firestore, en cambio, la relación entre consulta e índice es mucho más estricta. Si la estructura requerida no existe, la consulta falla y el sistema devuelve un mensaje para crear el índice faltante.[cite:2]
Además, los índices no solo mejoran lecturas. También tienen costo. La guía oficial de buenas prácticas indica que el principal contribuyente a la latencia de escritura es el index fanout, es decir, la cantidad de trabajo adicional que una escritura genera sobre índices asociados.[cite:1] La documentación de facturación añade que también se cobra por almacenamiento de base de datos, incluidos metadatos e índices, y por entradas de índice leídas en ciertos tipos de consulta.[cite:3]
Por eso, hablar de índices en Firestore no es hablar de un detalle secundario. Es hablar del núcleo de su arquitectura operativa. En este capítulo se estudiará cómo funciona el sistema de indexación, cómo administrarlo profesionalmente y cómo aplicarlo a las consultas reales del proyecto del libro: usuarios, instituciones, docentes, alumnos, grupos, cursos, clases, tareas, evidencias, archivos y notificaciones.
Desarrollo completo¶
¿Qué es un índice?¶
Un índice es una estructura de apoyo que permite localizar documentos de forma eficiente según el valor de uno o varios campos. En términos sencillos, es una representación organizada de datos pensada no para mostrar documentos completos, sino para encontrar rápido cuáles documentos cumplen una condición y en qué orden deben devolverse.
En Firestore, el índice no es opcional. La documentación oficial de administración de índices afirma que Firestore garantiza el rendimiento de las consultas exigiendo un índice para cada una de ellas.[cite:2] Eso quiere decir que cada búsqueda que el lector construye con where(), orderBy() o combinaciones más complejas necesita poder resolverse con ayuda de una estructura indexada.
Desde la perspectiva didáctica, puede pensarse en un índice como un catálogo técnico. El documento completo sería el libro; el índice sería la tabla que permite localizar rápidamente todos los libros ordenados por autor, por tema o por fecha. Sin ese catálogo, el sistema tendría que revisar manualmente demasiados elementos o, en el caso de Firestore, directamente impedir la consulta.
¿Por qué Firestore necesita índices?¶
Firestore fue diseñado como una base de datos documental distribuida, optimizada para escalabilidad, baja latencia y consultas predecibles. Para sostener esas propiedades en grandes volúmenes de datos, no puede depender de recorridos libres y costosos como si se tratara de una exploración completa de documentos.
La documentación oficial resume esta filosofía de manera directa: los índices requeridos por las consultas básicas se crean automáticamente, y cuando una consulta compuesta no puede resolverse con los índices existentes, el sistema devuelve un error con un enlace directo para crear el índice faltante.[cite:2] Esta conducta muestra que el motor de Firestore no “intenta” improvisar una solución lenta. Prefiere exigir la estructura correcta.
Esta decisión ofrece varias ventajas:
- Hace que el rendimiento de consulta sea más predecible.
- Reduce la necesidad de exploraciones costosas sobre grandes volúmenes documentales.
- Obliga a modelar datos y consultas con disciplina.
- Permite escalar sin caer tan fácilmente en degradaciones impredecibles.
La contrapartida es que el desarrollador debe comprender bien cómo consulta y qué estructura necesita.
¿Cómo funciona internamente un índice?¶
La documentación oficial no describe Firestore como una caja negra mágica, pero sí ofrece suficientes pistas para entender su comportamiento interno. La guía de índices explica que para construir uno nuevo Firestore primero configura la estructura y luego realiza un backfill con los datos existentes, lo cual puede tardar minutos o más según la cantidad de documentos afectados.[cite:2] Esto implica que el índice almacena información derivada de los documentos ya presentes y la mantiene actualizada conforme la base cambia.
También sabemos, por la documentación de precios, que una consulta puede cobrar por entradas de índice leídas, además de documentos.[cite:3] Esto revela un punto esencial: el motor consulta primero estructuras de índice para determinar candidatos y solo después materializa los documentos necesarios. No empieza leyendo documentos completos indiscriminadamente.
Desde una perspectiva conceptual, el funcionamiento general se parece a esto:
- La aplicación envía una consulta mediante el SDK.
- Firestore identifica qué campos, filtros y ordenamientos participan.
- Busca un índice compatible con esa estructura.
- Recorre entradas del índice para localizar el subconjunto relevante.[cite:3]
- Recupera los documentos candidatos.
- Devuelve los resultados o rechaza la consulta si no existe índice adecuado.[cite:2]
Por eso, el diseño de índices está íntimamente unido al diseño de consultas.
Indexación automática¶
Firestore crea automáticamente los índices necesarios para las consultas más básicas.[cite:2] Esto cubre gran parte de la experiencia inicial del desarrollador y explica por qué muchas búsquedas simples funcionan desde el primer momento.
Sin embargo, “automática” no significa “infinita”. La guía de buenas prácticas deja claro que para la mayoría de las aplicaciones puede confiarse en la indexación automática y en los enlaces de error para gestionar índices adicionales, pero también recomienda exenciones de índices de un solo campo en ciertos casos para reducir costos y mejorar latencia de escritura.[cite:1]
Es decir, la indexación automática es un punto de partida, no una estrategia profesional completa.
Índices simples¶
Un índice simple o de un solo campo organiza valores de un único campo para soportar búsquedas básicas, ordenamientos directos y ciertas consultas elementales. En Firestore, estos índices forman parte del comportamiento automático del sistema.[cite:2]
Por ejemplo, si en el proyecto del libro la colección usuarios contiene el campo rol, la base puede usar indexación simple para consultas como estas:
import { collection, query, where, getDocs } from 'firebase/firestore';
async function obtenerDocentes() {
const q = query(collection(db, 'usuarios'), where('rol', '==', 'docente'));
const snapshot = await getDocs(q);
return snapshot.docs.map(d => ({ id: d.id, ...d.data() }));
}
Este tipo de consulta rara vez requiere que el lector cree un índice compuesto manualmente, porque el sistema suele cubrirla con indexación automática.
Índices compuestos¶
Los índices compuestos organizan varios campos en una misma estructura para soportar consultas con combinaciones más complejas de filtros y ordenamientos. La referencia oficial de definición de índices muestra precisamente que un índice puede declararse con collectionGroup, queryScope y una lista ordenada de fields, lo cual refleja la estructura del índice compuesto.[cite:4]
La guía de administración de índices señala que si se intenta una consulta compuesta con una cláusula de rango que no coincide con un índice existente, Firestore devuelve un error con un enlace para crear el índice faltante.[cite:2] Esa es la señal más visible de que una consulta ha superado las capacidades del soporte automático.
Ejemplo típico del proyecto:
import { collection, query, where, orderBy, getDocs } from 'firebase/firestore';
async function obtenerTareasActivasPorCurso(cursoId, fechaActual) {
const q = query(
collection(db, 'tareas'),
where('cursoId', '==', cursoId),
where('fechaEntrega', '>=', fechaActual),
orderBy('fechaEntrega')
);
const snapshot = await getDocs(q);
return snapshot.docs.map(d => ({ id: d.id, ...d.data() }));
}
Esta consulta combina un filtro por igualdad, un filtro por rango y un ordenamiento. Dependiendo de la estructura ya existente, probablemente requiera un índice compuesto explícito.
Índices de Collection Group¶
Firestore también soporta consultas de grupo de colección, es decir, búsquedas que atraviesan todas las subcolecciones con el mismo nombre en la base. La referencia REST oficial distingue claramente el alcance COLLECTION del alcance COLLECTION_GROUP, indicando que un índice puede habilitar consultas contra una colección específica o contra todas las colecciones descendientes con el mismo ID.[cite:5]
En el proyecto del libro, esto es muy útil para entidades como clases o notificaciones distribuidas jerárquicamente.
import { collectionGroup, query, where, orderBy, getDocs } from 'firebase/firestore';
async function obtenerClasesPublicadasPorInstitucion(institucionId) {
const q = query(
collectionGroup(db, 'clases'),
where('institucionId', '==', institucionId),
orderBy('fechaProgramada', 'desc')
);
const snapshot = await getDocs(q);
return snapshot.docs.map(d => ({ id: d.id, ...d.data() }));
}
Este tipo de consulta suele apoyarse en índices específicos de COLLECTION_GROUP.[cite:4][cite:5]
Creación automática de índices desde errores de consulta¶
Una de las mejores experiencias de desarrollo que ofrece Firestore es que, cuando falta un índice para una consulta compuesta, el sistema devuelve un mensaje con un enlace directo a Firebase Console para crearlo.[cite:2]
Este comportamiento cumple dos funciones pedagógicas y operativas:
- Informa exactamente qué estructura necesita la consulta.
- Reduce la fricción de administración, porque la consola ya aparece prellenada con la configuración necesaria.[cite:2]
En proyectos reales esto ahorra tiempo, pero no debe conducir a crear índices sin criterio. Cada índice nuevo incrementa almacenamiento y puede aumentar latencia de escritura por mayor fanout.[cite:1][cite:3]
Creación manual de índices¶
No siempre conviene esperar a que la aplicación falle en tiempo de ejecución para descubrir un índice faltante. En equipos profesionales, es mejor anticipar consultas críticas y crear manualmente sus índices durante la preparación del entorno.
La documentación oficial indica que para crear un índice manualmente desde Firebase Console se debe entrar a Databases & Storage > Firestore > Indexes, seleccionar Add Index, indicar el nombre de la colección y configurar los campos.[cite:2]
La creación manual resulta especialmente valiosa cuando:
- El equipo ya conoce las consultas clave del sistema.
- Se desea preparar staging o producción antes del despliegue.
- Se trabaja con infraestructura versionada mediante CLI.
- Se quiere evitar errores funcionales en demostraciones o ambientes críticos.
Eliminación de índices¶
Los índices también se eliminan. La documentación oficial muestra que desde la consola puede borrarse un índice desde la pestaña Indexes, eligiendo Delete y confirmando la acción.[cite:2]
Eliminar índices no es una tarea cosmética. Tiene dos motivaciones importantes:
- Reducir almacenamiento innecesario.[cite:3]
- Reducir fanout de escritura cuando ciertos índices ya no aportan valor.[cite:1]
No obstante, eliminar un índice sin revisar consultas dependientes puede romper funcionalidades existentes. En entornos profesionales, conviene auditar primero el uso real de las consultas antes de limpiar índices.
Administración de índices¶
Administrar índices significa mucho más que crearlos. Implica:
- Revisar qué consultas críticas existen en la aplicación.
- Entender cuáles usan indexación automática y cuáles requieren índices compuestos.
- Vigilar el estado de construcción de nuevos índices.[cite:2]
- Mantener sincronía entre consola y archivos de infraestructura.[cite:2][cite:4]
- Eliminar estructuras que encarecen escrituras sin aportar valor.
Además, la documentación explica que la construcción de índices es una operación de larga duración. Puede listarse con gcloud firestore operations list y consultarse su estado con gcloud firestore operations describe.[cite:2] Esto es importante en proyectos grandes, porque un índice no está listo inmediatamente después de pulsar Create.
Archivo firestore.indexes.json¶
La CLI de Firebase permite gestionar índices como infraestructura versionada. La documentación oficial indica que al ejecutar firebase init firestore en el proyecto se genera un archivo JSON con los índices predeterminados en el formato correcto, y que luego puede editarse para agregar más índices y desplegarlos con firebase deploy.[cite:2]
La referencia oficial de definición de índices documenta precisamente la estructura esperada del archivo, con secciones como indexes y fieldOverrides.[cite:4]
Ejemplo conceptual para el proyecto del libro:
{
"indexes": [
{
"collectionGroup": "tareas",
"queryScope": "COLLECTION",
"fields": [
{ "fieldPath": "cursoId", "order": "ASCENDING" },
{ "fieldPath": "fechaEntrega", "order": "ASCENDING" }
]
},
{
"collectionGroup": "clases",
"queryScope": "COLLECTION_GROUP",
"fields": [
{ "fieldPath": "institucionId", "order": "ASCENDING" },
{ "fieldPath": "fechaProgramada", "order": "DESCENDING" }
]
}
],
"fieldOverrides": []
}
Este archivo debe formar parte del repositorio del proyecto, igual que las reglas de seguridad.
Despliegue de índices mediante Firebase CLI¶
La documentación oficial indica que es posible desplegar índices con Firebase CLI y que, para publicar solo índices y reglas, se puede usar la bandera --only firestore.[cite:2]
Ejemplo de flujo profesional:
Este enfoque tiene ventajas importantes:
- Mantiene los índices versionados.
- Permite replicar ambientes de desarrollo, pruebas y producción.
- Reduce dependencia de configuraciones manuales hechas solo en la consola.
- Facilita revisiones por equipo mediante control de versiones.
En un proyecto serio, la consola es útil para inspección y reacción rápida. La CLI es mejor para repetibilidad y gobierno técnico.
Consultas que requieren índices compuestos¶
No toda consulta necesita un índice compuesto, pero muchas búsquedas reales sí. La documentación de gestión de índices destaca expresamente las consultas compuestas con cláusulas de rango como candidatas a error por índice faltante.[cite:2]
En el proyecto del libro, suelen requerir especial atención consultas como estas:
- Tareas por
cursoId, filtradas además por estado y ordenadas por fecha de entrega. - Alumnos por
institucionIdyactivo, ordenados por nombre. - Clases por
institucionIdencollectionGroup, ordenadas por fecha. - Notificaciones no leídas por usuario, ordenadas por fecha de creación.
Cada una combina múltiples dimensiones de filtrado u ordenamiento y, por tanto, debe analizarse como candidata a índice compuesto.
Cómo interpretar los mensajes de error¶
Cuando falta un índice, Firestore no devuelve un error genérico impreciso. La documentación explica que el mensaje incluye un enlace directo para crear el índice requerido en Firebase Console.[cite:2] Esta es una de las señales más útiles para el desarrollador.
Interpretar bien ese mensaje significa entender varias cosas:
- La consulta es válida en términos de sintaxis.
- El problema no es el SDK ni la autenticación.
- Firestore necesita una estructura adicional para garantizar rendimiento.
- El enlace propuesto describe exactamente una solución posible.[cite:2]
En el caso de índices vectoriales, el mismo documento indica que el error puede incluir un comando de Google Cloud CLI en lugar de un enlace directo de consola.[cite:2] Aunque este manual se centra en consultas documentales clásicas, el principio es el mismo: no falta “permiso para consultar”; falta “estructura para consultar”.
Rendimiento de consultas indexadas¶
El beneficio principal de un índice es que permite encontrar documentos relevantes sin depender de exploraciones amplias o trabajo manual del cliente. Por eso Firestore exige índices para mantener el rendimiento de consulta.[cite:2]
En términos prácticos, una consulta bien indexada ofrece:
- Menor latencia percibida.
- Mejor escalabilidad a medida que la colección crece.
- Menor presión sobre cliente y red porque devuelve exactamente lo que se pidió.
- Menor necesidad de postprocesamiento en frontend.
La documentación de buenas prácticas también sugiere usar cursores en lugar de offsets, porque los offsets siguen recuperando internamente los documentos omitidos, afectando latencia y facturación.[cite:1] Esto se conecta con la idea de rendimiento: no basta con “tener índice”; también hay que consultar de forma inteligente.
Rendimiento de consultas sin índice¶
En Firestore, una consulta verdaderamente sin índice adecuado no suele degradarse simplemente: falla. Esa es una diferencia importante frente a otros motores. La guía de índices señala que si una consulta compuesta con rango no mapea a un índice existente, se recibe un error.[cite:2]
Esto tiene una implicación positiva: el sistema evita que una mala consulta se convierta silenciosamente en una operación muy lenta y costosa. Pero también implica una responsabilidad: el diseño del acceso a datos debe madurar junto con el modelo y no después.
En escenarios donde sí existe algún soporte parcial, pero la consulta o el patrón de acceso es ineficiente, el problema se expresa como mayor latencia, más lecturas o más costo, no necesariamente como error sintáctico.
Costos asociados a la indexación¶
La indexación tiene costos de varias clases:
- Costo de almacenamiento. La documentación de precios especifica que se cobra por la cantidad de almacenamiento usada por la base de datos, incluidos metadatos e índices.[cite:3]
- Costo de escritura indirecto. La guía de buenas prácticas afirma que la principal causa de latencia de escritura es el index fanout.[cite:1] Más índices significan más trabajo por cada escritura.
- Costo de lectura de índices. La documentación de facturación aclara que ciertas consultas también cobran lecturas de entradas de índice.[cite:3]
Por tanto, cada índice agrega valor potencial, pero también peso operativo.
Impacto de los índices sobre almacenamiento¶
Cuando se habla de “crear un índice” a veces se piensa solo en la capacidad de consulta. Pero un índice también ocupa espacio. La documentación de precios lo deja claro al incluir metadatos e índices dentro del almacenamiento facturable.[cite:3]
Esto es especialmente relevante cuando se indexan:
- Campos de texto muy largos.
- Arrays grandes.
- Maps extensos.
- Campos que nunca se usan en consultas.
La guía de buenas prácticas recomienda exenciones de índice precisamente para campos largos, arrays o mapas grandes y ciertos campos secuenciales que no se consultan.[cite:1] Esta es una herramienta poderosa para contener costos y fanout.
Optimización de consultas¶
Optimizar una consulta en Firestore no significa solo hacerla “más rápida”. Significa mejorar simultáneamente rendimiento, costo y sostenibilidad del sistema. Algunas estrategias oficiales y prácticas son estas:
- Usar cursores y no offsets.[cite:1]
- Reducir campos indexados innecesarios con exenciones cuando no participen en búsquedas.[cite:1]
- Diseñar consultas con límites claros.
- Evitar colecciones con accesos concentrados en rangos lexicográficamente cercanos cuando el tráfico es muy alto.[cite:1]
- Modelar documentos pensando primero en cómo se consultarán.
En aplicaciones del libro, esto se traduce en preguntas concretas: ¿realmente el panel necesita 500 alumnos de golpe? ¿la pantalla de tareas requiere tiempo real o basta una carga puntual? ¿ese campo de descripción larga necesita indexarse?
Estrategias para reducir lecturas¶
Aunque este capítulo se centra en índices, optimizar lecturas también forma parte del diseño de consulta. La guía de buenas prácticas y la de facturación ofrecen principios muy útiles:
- Evitar offsets, porque se cobran documentos omitidos.[cite:1][cite:3]
- Utilizar cursores para paginación escalable.[cite:1]
- Aplicar
limit()siempre que la interfaz no necesite el conjunto completo. - Consultar por ID cuando ya se conoce el documento exacto.
- Evitar listeners en tiempo real sobre conjuntos muy grandes si no aportan valor continuo.[cite:3]
- Diseñar vistas de resumen con documentos agregados o proyecciones cuando el caso de uso lo justifique.
Reducir lecturas no es “ahorrar por ahorrar”; es alinear el consumo de datos con la necesidad real del producto.
Estrategias para reducir índices innecesarios¶
La documentación oficial propone exenciones de índices de un solo campo en escenarios muy concretos.[cite:1] Algunas estrategias derivadas son:
- Excluir de indexación campos de texto extensos que solo se muestran, pero no se filtran.[cite:1]
- Excluir campos secuenciales como timestamps cuando no se consultan y están generando presión sobre escrituras.[cite:1]
- Excluir grandes arrays o maps si no participan en filtros.[cite:1]
- Desactivar índices descendentes y de arrays a nivel de colección cuando no aportan valor, como sugiere la guía para reducir fanout.[cite:1]
Estas decisiones pueden bajar almacenamiento y latencia de escritura de forma considerable.
Limitaciones del sistema de indexación¶
El sistema de indexación de Firestore es muy potente, pero no ilimitado. La propia documentación de índices advierte que una operación de construcción puede fallar si se alcanzan límites de indexación, por ejemplo el número máximo de entradas de índice por documento.[cite:2] La guía de buenas prácticas también menciona que arrays y maps grandes pueden acercarse al límite de 40,000 entradas de índice por documento.[cite:1]
Otras limitaciones importantes son:
- Un índice tarda tiempo en construirse; no está disponible instantáneamente.[cite:2]
- Más índices implican mayor costo de almacenamiento y más trabajo de escritura.[cite:1][cite:3]
- Los índices compuestos deben diseñarse exactamente según el patrón real de consulta.[cite:2][cite:4]
- Los campos secuenciales muy indexados pueden crear cuellos de botella de escritura en colecciones de alto tráfico.[cite:1]
Ejemplos paso a paso¶
Ejemplo 1: consulta que falla por índice compuesto faltante¶
import { collection, query, where, orderBy, getDocs } from 'firebase/firestore';
async function obtenerTareasPendientes(cursoId, fechaActual) {
const q = query(
collection(db, 'tareas'),
where('cursoId', '==', cursoId),
where('fechaEntrega', '>=', fechaActual),
orderBy('fechaEntrega')
);
return getDocs(q);
}
Qué ocurre internamente: Firestore intenta mapear esta consulta a los índices disponibles. Si no existe la combinación adecuada, devuelve un error con un enlace de creación automática.[cite:2]
Ejemplo 2: definición del índice en firestore.indexes.json¶
{
"indexes": [
{
"collectionGroup": "tareas",
"queryScope": "COLLECTION",
"fields": [
{ "fieldPath": "cursoId", "order": "ASCENDING" },
{ "fieldPath": "fechaEntrega", "order": "ASCENDING" }
]
}
],
"fieldOverrides": []
}
Qué resuelve: documenta y despliega la estructura necesaria para la consulta anterior.[cite:2][cite:4]
Ejemplo 3: despliegue por CLI¶
Qué resuelve: publica índices y reglas de Firestore desde la infraestructura versionada.[cite:2]
Ejemplo 4: Collection Group index para clases¶
{
"indexes": [
{
"collectionGroup": "clases",
"queryScope": "COLLECTION_GROUP",
"fields": [
{ "fieldPath": "institucionId", "order": "ASCENDING" },
{ "fieldPath": "fechaProgramada", "order": "DESCENDING" }
]
}
],
"fieldOverrides": []
}
Qué resuelve: habilita un panel administrativo transversal de clases por institución.[cite:4][cite:5]
Ejemplo 5: exención de campo largo no consultado¶
Supongamos que la colección tareas incluye un campo descripcionLarga con mucho texto, pero nunca se usa en búsquedas. La guía de buenas prácticas recomienda excluir de indexación campos string largos si no se consultan.[cite:1]
Qué resuelve: reduce almacenamiento y fanout de escritura.
Comparaciones técnicas¶
Índice simple vs índice compuesto¶
| Tipo | Qué indexa | Cuándo conviene | Riesgo si se abusa |
|---|---|---|---|
| Índice simple | Un solo campo | Consultas básicas y ordenamientos simples | Storage y fanout innecesario si el campo nunca se consulta |
| Índice compuesto | Varios campos en orden específico | Consultas compuestas reales, filtros + ordenamientos | Multiplicar estructuras poco usadas y encarecer escrituras |
Console vs CLI para administrar índices¶
| Herramienta | Fortalezas | Debilidad principal |
|---|---|---|
| Firebase Console | Rapidez, inspección visual, creación desde errores | Cambios manuales fáciles de olvidar en control de versiones |
| Firebase CLI | Repetibilidad, versionado, despliegue por ambiente | Requiere más disciplina técnica |
Índice útil vs índice innecesario¶
| Criterio | Índice útil | Índice innecesario |
|---|---|---|
| Consulta asociada | Existe y es frecuente | No hay uso real confirmado |
| Impacto en lectura | Reduce latencia y habilita consultas | Nulo |
| Impacto en escritura | Justificado | Solo aumenta fanout |
| Impacto en storage | Aceptable | Costo sin retorno |
Casos prácticos¶
Caso 1: panel de alumnos por institución¶
Consulta frecuente:
institucionId == Xactivo == trueorderBy(displayName)
Análisis: es una consulta de panel administrativo muy frecuente. Conviene un índice compuesto porque será usada repetidamente y debe escalar con muchos alumnos.
Caso 2: tareas activas por curso¶
Consulta frecuente:
cursoId == XfechaEntrega >= hoyorderBy(fechaEntrega)limit(20)
Análisis: es un patrón claro de calendario y seguimiento académico. Requiere indexación precisa y se beneficia mucho de límites cortos para reducir lecturas.
Caso 3: notificaciones en tiempo real¶
Consulta frecuente:
- subcolección
notificaciones leida == falseorderBy(createdAt, 'desc')
Análisis: aquí el índice no solo habilita la consulta. También importa decidir si el listener en tiempo real debe mantenerse activo permanentemente. La documentación de facturación advierte que los listeners generan lecturas cuando cambian los documentos del conjunto.[cite:3]
Caso 4: clases globales con Collection Group¶
Consulta frecuente:
collectionGroup('clases')institucionId == XorderBy(fechaProgramada, 'desc')
Análisis: ideal para un dashboard centralizado de operación académica. Requiere un índice de COLLECTION_GROUP.[cite:4][cite:5]
Buenas prácticas¶
- Confiar en la indexación automática para lo básico, pero diseñar índices compuestos de forma deliberada para consultas críticas.[cite:2]
- Mantener
firestore.indexes.jsonversionado junto con reglas y configuración del proyecto.[cite:2][cite:4] - Revisar los enlaces de error antes de crear índices indiscriminadamente; entender qué consulta los requiere.[cite:2]
- Excluir campos largos, arrays grandes o campos secuenciales no consultados cuando generan fanout o costo de almacenamiento.[cite:1]
- Usar cursores en lugar de offsets para mejorar rendimiento y reducir lecturas facturables.[cite:1][cite:3]
- Evaluar cada índice nuevo no solo por la lectura que habilita, sino por el costo de escritura y almacenamiento que añade.[cite:1][cite:3]
- Preparar los índices del ambiente productivo antes de activar funcionalidades críticas.
- Monitorear tiempos de construcción y estado de índices en operaciones de gran volumen.[cite:2]
Errores comunes¶
- Crear índices solo cuando producción ya está fallando.
- Pensar que más índices siempre significan mejor rendimiento.
- Olvidar que cada índice aumenta almacenamiento y fanout.[cite:1][cite:3]
- Mantener indexados campos largos que nunca se consultan.[cite:1]
- No versionar
firestore.indexes.json. - Hacer cambios manuales en consola y no replicarlos en el repositorio.[cite:2]
- Intentar resolver problemas de modelado solo agregando índices.
- Usar offsets en listas grandes y culpar al índice del costo excesivo.[cite:1][cite:3]
- No considerar que la construcción de índices toma tiempo y puede requerir backfill significativo.[cite:2]
Resumen¶
Cloud Firestore necesita índices para garantizar el rendimiento de todas sus consultas, y por eso el sistema crea automáticamente los necesarios para búsquedas básicas y exige índices adicionales para consultas compuestas o más avanzadas.[cite:2] Esta arquitectura hace que la indexación no sea un detalle opcional, sino un componente central del diseño de datos y del rendimiento de la aplicación.
Los índices simples permiten resolver consultas elementales sobre un solo campo, mientras que los índices compuestos habilitan combinaciones de filtros y ordenamientos más complejas, incluidas consultas sobre Collection Group con alcances específicos.[cite:2][cite:4][cite:5] Su administración puede realizarse desde Firebase Console o mediante infraestructura versionada con firestore.indexes.json y Firebase CLI, lo cual resulta especialmente importante en equipos y ambientes múltiples.[cite:2][cite:4]
Sin embargo, indexar también cuesta. Los índices incrementan almacenamiento facturable, pueden generar lecturas de entradas de índice en ciertas consultas y aumentan la latencia de escritura a través del index fanout.[cite:1][cite:3] Por eso, optimizar Firestore significa elegir bien qué indexar, qué excluir, cómo consultar, cómo paginar y cómo alinear la base de datos con los patrones reales de acceso del producto.
Conceptos clave¶
- Índice.
- Indexación automática.[cite:2]
- Índice simple.
- Índice compuesto.[cite:2][cite:4]
- Collection Group index.[cite:4][cite:5]
firestore.indexes.json.[cite:2][cite:4]firebase deploy --only firestore.[cite:2]- Backfill de índices.[cite:2]
- Operaciones de larga duración para construcción de índices.[cite:2]
- Index fanout.[cite:1]
- Exenciones de índices de un solo campo.[cite:1]
- Lecturas de entradas de índice.[cite:3]
- Costo de almacenamiento de índices.[cite:3]
- Optimización de consultas.
- Paginación con cursores.[cite:1]
Preguntas de repaso¶
- ¿Por qué Firestore exige un índice para cada consulta?[cite:2]
- ¿Qué diferencia existe entre indexación automática e índice compuesto?
- ¿Cuándo conviene crear un índice manualmente en lugar de esperar al error en tiempo de ejecución?[cite:2]
- ¿Qué papel cumple
firestore.indexes.jsonen un flujo profesional de desarrollo?[cite:2][cite:4] - ¿Por qué demasiados índices pueden empeorar la latencia de escritura?[cite:1]
- ¿Qué tipos de campos suelen ser candidatos a exención de indexación?[cite:1]
- ¿Cómo afecta el almacenamiento de índices al costo operativo?[cite:3]
- ¿Qué diferencia existe entre un índice
COLLECTIONy unoCOLLECTION_GROUP?[cite:5] - ¿Qué ocurre internamente mientras se construye un índice nuevo?[cite:2]
- ¿Por qué un mal patrón de paginación puede aumentar costo incluso si existe el índice correcto?[cite:1][cite:3]
Ejercicios prácticos¶
- Diseña el índice compuesto necesario para una consulta de alumnos por
institucionId,activoy orden pordisplayName. - Crea un ejemplo de
firestore.indexes.jsonque incluya un índice deCOLLECTION_GROUPparaclases.[cite:4] - Analiza una colección del proyecto con un campo de texto largo y justifica si debe quedar exento de indexación.[cite:1]
- Reescribe una consulta paginada usando cursores en lugar de offsets y explica cómo mejora rendimiento y costo.[cite:1][cite:3]
- Simula el flujo completo desde un error por índice faltante hasta su creación y despliegue por CLI.[cite:2]
- Identifica tres índices del proyecto transversal que sí aportan valor y dos que sería mejor evitar, justificando costo, frecuencia de uso y fanout.
- Investiga cómo monitorizar el progreso de construcción de un índice con
gcloud firestore operations describey explica cuándo sería útil.[cite:2] - Evalúa si una consulta en tiempo real sobre notificaciones necesita además una reducción de tamaño del resultado para contener costos.[cite:3]
Bibliografía y referencias oficiales¶
- Best practices for Cloud Firestore: https://firebase.google.com/docs/firestore/best-practices [cite:1]
- Manage indexes in Cloud Firestore: https://firebase.google.com/docs/firestore/query-data/indexing [cite:2]
- Understand Cloud Firestore billing: https://firebase.google.com/docs/firestore/pricing [cite:3]
- Cloud Firestore Index Definition Reference: https://firebase.google.com/docs/reference/firestore/indexes [cite:4]
- Firestore collection group index scope reference: https://docs.cloud.google.com/firestore/docs/reference/rest/v1beta2/projects.databases.collectionGroups.indexes [cite:5]