Descripción general de la indexación

Los índices son un factor importante del rendimiento de las bases de datos. Al igual que el índice de un libro que indica en qué página se encuentra cada tema, el índice de una base de datos se encarga de ordenar todos los elementos en su ubicación respectiva. Cuando envías una consulta a una base de datos, esta puede usar el índice para buscar rápidamente los elementos que solicitaste.

En esta página, se describen los dos tipos de índices que usa Firestore: los de campo único y los compuestos.

Un índice para cada consulta

Si se hace una consulta sin índice, la mayoría de las bases de datos rastreará su contenido elemento por elemento. Este proceso es muy lento y empeora a medida que aumenta el tamaño de la base de datos. Firestore garantiza un alto rendimiento, ya que usa índices en todas las consultas. Por lo tanto, el rendimiento de las consultas depende del tamaño del conjunto de resultados y no de la cantidad de elementos que se encuentran en la base de datos.

Dedica menos tiempo a la administración de índices y más al desarrollo de apps

Firestore tiene funciones que reducen el tiempo necesario para administrar los índices. Crea de forma automática los índices necesarios para las consultas más básicas. A medida que usas y pruebas tu app, Firestore te ayudará a identificar y crear los índices adicionales necesarios.

Tipos de índices

Firestore usa dos tipos de índices: los de campo único y los compuestos. Además de la cantidad de campos indexados, los índices de campo único y compuestos se administran de manera distinta.

Índices de campo único

Un índice de campo único almacena el orden de todos los documentos en una colección con un campo específico. Todas las entradas de un índice de campo único registran el valor de un documento en un campo específico y su ubicación en la base de datos. Firestore usa estos índices para realizar muchas consultas básicas. Para administrar los índices de campo único, puedes configurar la indexación automática de tu base de datos y las exenciones de índices.

Indexación automática

Según la configuración predeterminada, Firestore mantiene de forma automática un índice de campo único para cada campo de un documento y cada subcampo de un mapa. Firestore usa la siguiente configuración predeterminada para los índices de campo único:

  • En los campos que no son de arreglo ni de mapa, Firestore define dos índices de campo único con alcance de colección: uno en modo ascendente y otro en modo descendente.

  • En los campos de mapa, Firestore crea un índice ascendente con alcance de colección y uno descendente para cada subcampo que no sea de mapa ni de arreglo.

  • En cada campo de arreglo de un documento, Firestore crea y mantiene un índice de contenido de arreglo con alcance de colección.

  • Según la configuración predeterminada, no se mantienen los índices de campo único con alcance del grupo de colección.

Exenciones de índices de campo único

Para eximir un campo de tu configuración de indexación automática, crea una exención del índice de campo único. Esta opción anula la configuración de índice automático de la base de datos. Una exención puede habilitar un índice de campo único que, de lo contrario, se inhabilitaría por tu configuración de indexación automática, o viceversa. Consulta las prácticas recomendadas de indexación para saber en qué casos podrían ser útiles las exenciones.

Si creas una exención de un índice de campo único para un campo de mapa, sus subcampos heredarán esta configuración. Sin embargo, puedes definir exenciones de índices de campo único para subcampos específicos. Si borras la exención de un subcampo, este heredará la configuración de la exención principal (si tienes una) o, de lo contrario, heredará la de la base de datos.

Para crear y administrar las exenciones de índice de campo único, consulta Administra índices en Firestore.

Índices compuestos

Un índice compuesto almacena el orden de todos los documentos en una colección, según una lista ordenada de los campos que se indexarán.

Firestore usa índices compuestos para admitir consultas que no se pueden realizar en un índice de campo único.

Firestore no crea de forma automática los índices compuestos, como lo hace con los de campo único, debido a la gran cantidad de combinaciones posibles de los campos. En lugar de eso, Firestore te ayuda a identificar y crear los índices compuestos necesarios mientras compilas tu app.

Si intentas realizar la consulta anterior sin haber creado el índice necesario, Firestore mostrará un mensaje de error con un vínculo que podrás usar para crear el índice. Esto ocurre cada vez que intentas realizar una consulta que no es compatible con un índice. También puedes definir y administrar los índices compuestos de forma manual con la consola o Firebase CLI. Para obtener más información sobre cómo crear y administrar índices compuestos, consulta este artículo.

Modos de índice y alcances de las consultas

Los índices de campo único y los compuestos se configuran de manera distinta, pero ambos requieren que ajustes los modos de índice y alcances de las consultas.

Modos de índice

Cuando se define un índice, se selecciona un modo de índice para cada campo indexado. El modo de índice de cada campo admite cláusulas específicas de consultas en ese campo. Puedes seleccionar las siguientes opciones:

Modo de índice Descripción
Ascendente Admite cláusulas de consulta <, <=, ==, >=, > y in en el campo, así como el orden ascendente según el valor del campo.
Descendente Admite cláusulas de consulta <, <=, ==, >=, > y in en el campo, así como el orden descendente según el valor del campo.
Contenido del arreglo Admite cláusulas de consulta array-contains y array-contains-any en el campo.

Alcances de las consultas

Cada índice se limita a una colección o a un grupo de colecciones. Esto se conoce como el alcance de la consulta del índice:

Alcance de la colección
De forma predeterminada, Firestore crea índices con alcance de colección. Estos índices admiten consultas que muestran resultados de una sola colección.

Alcance del grupo de colección
Un grupo de colección incluye todas las colecciones con el mismo ID. Para ejecutar una consulta del grupo de colección que muestre resultados ordenados o filtrados de un grupo de colección, debes crear un índice correspondiente con el alcance del grupo de colección.

Ejemplo de indexación

Firestore crea los índices de campo único de forma automática, lo que permite que tu aplicación admita con rapidez los tipos de consultas de base de datos más básicos. Los índices de campo único te permiten ejecutar consultas simples basadas en los valores de campo y los comparadores <, <=, ==, >=, > y in. En los campos de arreglo, te permiten ejecutar consultas de array-contains y array-contains-any.

A modo de referencia, consulta los siguientes ejemplos desde la perspectiva de la creación de índices. En el siguiente ejemplo, se crean algunos documentos de city en una colección de cities y se configuran los campos name, state, country, capital, population y tags para cada documento:

Web
var citiesRef = db.collection("cities");

citiesRef.doc("SF").set({
    name: "San Francisco", state: "CA", country: "USA",
    capital: false, population: 860000,
    regions: ["west_coast", "norcal"] });
citiesRef.doc("LA").set({
    name: "Los Angeles", state: "CA", country: "USA",
    capital: false, population: 3900000,
    regions: ["west_coast", "socal"] });
citiesRef.doc("DC").set({
    name: "Washington, D.C.", state: null, country: "USA",
    capital: true, population: 680000,
    regions: ["east_coast"] });
citiesRef.doc("TOK").set({
    name: "Tokyo", state: null, country: "Japan",
    capital: true, population: 9000000,
    regions: ["kanto", "honshu"] });
citiesRef.doc("BJ").set({
    name: "Beijing", state: null, country: "China",
    capital: true, population: 21500000,
    regions: ["jingjinji", "hebei"] });

Con la configuración de indexación automática predeterminada como base, Firestore actualiza un índice de campo único ascendente y uno descendente por cada campo que no sea de arreglo y un índice de campo único con contenido del arreglo para el campo del arreglo. Cada fila de la siguiente tabla representa una entrada en un índice de campo único:

Colección Campo indexado Alcance de la consulta
cities name Colección
cities state Colección
cities country Colección
cities capital Colección
cities population Colección
cities name Colección
cities state Colección
cities country Colección
cities capital Colección
cities population Colección
cities array-contains regions Colección

Consultas compatibles con los índices de campo único

Puedes usar estos índices de campo único creados automáticamente para ejecutar consultas simples, como esta:

Web
citiesRef.where("state", "==", "CA")
citiesRef.where("population", "<", 100000)
citiesRef.where("name", ">=", "San Francisco")

También puedes crear consultas in y de igualdad compuesta (==):

Web
citiesRef.where('country', 'in', ["USA", "Japan", "China"])

// Compound equality queries
citiesRef.where("state", "==", "CO").where("name", "==", "Denver")
citiesRef.where("country", "==", "USA")
         .where("capital", "==", false)
         .where("state", "==", "CA")
         .where("population", "==", 860000)

Si necesitas ejecutar una consulta compuesta que use una comparación de rangos (<, <=, > o >=) o necesitas ordenar según otro campo, debes crear un índice compuesto para la consulta.

El índice de array-contains te permite realizar una consulta en el campo de arreglo regions:

Web
citiesRef.where("regions", "array-contains", "west_coast")
// array-contains-any and array-contains use the same indexes
citiesRef.where("regions", "array-contains-any", ["west_coast", "east_coast"])

Consultas compatibles con los índices compuestos

Firestore usa índices compuestos para admitir consultas compuestas que no se pueden realizar en un índice de campo único. Por ejemplo, debes tener un índice compuesto para realizar las siguientes consultas:

Web
citiesRef.where("country", "==", "USA").orderBy("population", "asc")
citiesRef.where("country", "==", "USA").where("population", "<", 3800000)
citiesRef.where("country", "==", "USA").where("population", ">", 690000)
// in and == clauses use the same index
citiesRef.where("country", "in", ["USA", "Japan", "China"])
         .where("population", ">", 690000)

Estas requieren el índice compuesto que se indica a continuación. Dado que la consulta utiliza una igualdad (== o in) para el campo country, puedes usar un modo de índice ascendente o descendente para este campo. Según la configuración predeterminada, las cláusulas con desigualdad aplicarán un orden ascendente según el campo que se indique en la cláusula.

Colección Campos indexados Alcance de la consulta
cities (o ) country, population Colección

Para ejecutar las mismas consultas, pero en orden descendente, necesitas otro índice compuesto en orden descendente para el valor population:

Web
citiesRef.where("country", "==", "USA").orderBy("population", "desc")

citiesRef.where("country", "==", "USA")
         .where("population", "<", 3800000)
         .orderBy("population", "desc")

citiesRef.where("country", "==", "USA")
         .where("population", ">", 690000)
         .orderBy("population", "desc")

citiesRef.where("country", "in", ["USA", "Japan", "China"])
         .where("population", ">", 690000)
         .orderBy("population", "desc")
Colección Campos indexados Alcance de la consulta
cities country, population Colección
cities country, population Colección

También deberás crear un índice compuesto para combinar una consulta de array-contains o array-contains-any con cláusulas adicionales.

Web
citiesRef.where("regions", "array-contains", "east_coast")
         .where("capital", "==", true)

// array-contains-any and array-contains use the same index
citiesRef.where("regions", "array-contains-any", ["west_coast", "east_coast"])
         .where("capital", "==", true)
Colección Campos indexados Alcance de la consulta
cities array-contains tags, (o ) capital Colección

Consultas compatibles con los índices del grupo de colecciones

Para demostrar un índice con alcance del grupo de colecciones, imagina que agregas una subcolección landmarks a algunos documentos de city:

Web
var citiesRef = db.collection("cities");

citiesRef.doc("SF").collection("landmarks").doc().set({
    name: "Golden Gate Bridge",
    category : "bridge" });
citiesRef.doc("SF").collection("landmarks").doc().set({
    name: "Golden Gate Park",
    category : "park" });

citiesRef.doc("DC").collection("landmarks").doc().set({
    name: "National Gallery of Art",
    category : "museum" });
citiesRef.doc("DC").collection("landmarks").doc().set({
    name: "National Mall",
    category : "park" });

Si usas el siguiente índice de campo único con alcance de colección, puedes consultar la colección landmarks de una sola ciudad según el campo category:

Colección Campos indexados Alcance de la consulta
puntos de referencia (o ) category Colección
Web
citiesRef.doc("SF").collection("landmarks").where("category", "==", "park")
citiesRef.doc("SF").collection("landmarks").where("category", "in", ["park", "museum"])

Ahora imagina que te interesa consultar los puntos de referencia de todas las ciudades. Para realizar esta consulta en un grupo que tenga todas las colecciones de landmarks, debes habilitar el índice de campo único landmarks con el alcance del grupo de colecciones:

Colección Campos indexados Alcance de la consulta
puntos de referencia (o ) category Grupo de colecciones

Con este índice habilitado, puedes consultar el grupo de colecciones landmarks:

Web
var landmarksGroupRef = db.collectionGroup("landmarks");

landmarksGroupRef.where("category", "==", "park")
landmarksGroupRef.where("category", "in", ["park", "museum"])

Para realizar una consulta en un grupo de colección que muestre resultados ordenados o filtrados, debes habilitar un índice de campo único o compuesto correspondiente con el alcance del grupo de colección. Sin embargo, las consultas que no ordenan ni filtran los comentarios, no requieren definiciones adicionales del índice.

Por ejemplo, puedes ejecutar la siguiente consulta en el grupo de colección sin habilitar un índice adicional:

Web
db.collectionGroup("landmarks").get()

Entradas de índice

Los índices configurados de tu proyecto y la estructura de un documento, afectan las entradas de índice del documento, que en última instancia se consideran para el límite de recuento de entradas del índice.

A continuación, se presenta un ejemplo a modo de ilustración.

Documento

name : "San Francisco"
temperatures : {summer: 67, winter: 55}
neighborhoods : ["Mission", "Downtown", "Marina"]

Índices de campo único

  • name ASC & DESC (automático)
  • temperatures ASC & DESC (automático)
  • neighborhoods Array Contains (automático)

Índices compuestos

  • name ASC, neighborhoods ASC
  • name DESC, neighborhoods ASC

Entradas de índice resultantes

Esta configuración de indexación da como resultado las siguientes 12 entradas de índice para el documento:

Índice Entrada
name ASC & DESC name: “San Francisco”
temperatures ASC & DESC temperatures.summer: 67
temperatures ASC & DESC temperatures.winter: 55
neighborhoods Array Contains neighborhoods: “Mission”
neighborhoods Array Contains neighborhoods: “Downtown”
neighborhoods Array Contains neighborhoods: “Marina”
name ASC, neighborhoods ASC name: “San Francisco”, neighborhoods: “Mission”
name ASC, neighborhoods ASC name: “San Francisco”, neighborhoods: “Downtown”
name ASC, neighborhoods ASC name: “San Francisco”, neighborhoods: “Marina”
name DESC, neighborhoods ASC name: “San Francisco”, neighborhoods: “Mission”
name DESC, neighborhoods ASC name: “San Francisco”, neighborhoods: “Downtown”
name DESC, neighborhoods ASC name: “San Francisco”, neighborhoods: “Marina”

Índices y precios

Los índices contribuyen a los costos de almacenamiento de tu aplicación. Para obtener más información sobre cómo se calcula el tamaño del almacenamiento de los índices, consulta Tamaño de una entrada del índice.

Aprovecha la combinación de índices

Firestore usa un índice para cada consulta, pero este no es un requisito. En el caso de las consultas con varias cláusulas de igualdad (==) y, de forma opcional, una cláusula orderBy, Firestore puede volver a usar los índices existentes. Firestore puede combinar los índices con filtros de igualdad simples a fin de crear los índices compuestos necesarios para realizar consultas con más cláusulas de igualdad.

A fin de reducir los costos de creación de los índices, identifica las situaciones en las que puedes combinar algunos de ellos. Por ejemplo, imagina una colección de restaurants en una app de calificación de restaurantes:

  • restaurants

    • burgerthyme

      name : "Burger Thyme"
      category : "burgers"
      city : "San Francisco"
      editors_pick : true
      star_rating : 4

Ahora imagina que esta app usa consultas como las que se indican a continuación. Ten en cuenta que la app usa combinaciones de cláusulas de igualdad para category, city y editors_pick, y un orden ascendente por star_rating.

Web
db.collection("restaurants").where("category", "==", "burgers")
                            .orderBy("star_rating")

db.collection("restaurants").where("city", "==", "San Francisco")
                            .orderBy("star_rating")

db.collection("restaurants").where("category", "==", "burgers")
                            .where("city", "==", "San Francisco")
                            .orderBy("star_rating")

db.collection("restaurants").where("category", "==", "burgers")
                            .where("city", "==" "San Francisco")
                            .where("editors_pick", "==", true )
                            .orderBy("star_rating")

Puedes crear un índice para cada consulta:

Colección Campos indexados Alcance de la consulta
restaurants category, star_rating Colección
restaurants city, star_rating Colección
restaurants category, city, star_rating Colección
restaurants category, city, editors_pick, star_rating Colección

Una mejor opción es aprovechar la función de Firestore para combinar índices según cláusulas de igualdad a fin de reducir la cantidad de índices:

Colección Campos indexados Alcance de la consulta
restaurants category, star_rating Colección
restaurants city, star_rating Colección
restaurants editors_pick, star_rating Colección

Este conjunto de índices no solo es más pequeño, sino que también admite una consulta adicional:

Web
db.collection("restaurants").where("editors_pick", "==", true)
                            .orderBy("star_rating")

Límites de indexación

Los siguientes límites se aplican a los índices. Consulta Cuotas y límites para obtener más información sobre este tema.

Límite Detalles
Cantidad máxima de índices compuestos que se permiten para una base de datos 200
Cantidad máxima de exenciones de índice de un único campo para una base de datos 200

Cantidad máxima de entradas de índice permitidas en cada documento

40,000

La cantidad de entradas de índice en cada documento es la suma de los siguientes elementos:

  • Cantidad de entradas en un índice de un único campo
  • Cantidad de entradas en un índice compuesto

Para ver cómo Firestore convierte un documento y un conjunto de índices en entradas en un índice, consulta este ejemplo de recuento de entradas de índice.

Tamaño máximo de una entrada de índice

7.5 KiB

Para saber cómo Firestore calcula el tamaño de las entradas en el índice, consulta Tamaño de una entrada del índice.

Suma máxima de los tamaños de las entradas en un índice de un documento

8 MiB

El tamaño total corresponde a la suma de los siguientes elementos de un documento:

  • La suma del tamaño de las entradas de índice de un único campo del documento
  • La suma del tamaño de las entradas de índice compuesto del documento
  • Tamaño máximo del valor de un campo indexado

    1,500 bytes

    Se reducirán los valores de campo que superen los 1,500 bytes. Es posible que las consultas que tengan valores de campo reducidos muestren resultados incoherentes.

    Recomendaciones sobre indexación

    En la mayoría de las apps, puedes confiar en la indexación automática y en los vínculos de los mensajes de error para administrar tus índices. Sin embargo, es posible que quieras agregar exenciones de campo único en los siguientes casos:

    Caso Descripción
    Campos de string grandes

    Si tienes un campo de string que suele tener valores de string largos que no usas para realizar consultas, exime al campo de la indexación a fin de reducir los costos de almacenamiento.

    Tasas altas de escritura en una colección que tiene documentos con valores secuenciales

    Si indexas un campo que aumenta o disminuye secuencialmente entre los documentos de una colección, como una marca de tiempo, la tasa máxima de escritura en la colección es de 500 operaciones de escritura por segundo. Si no realizas consultas basadas en campos con valores secuenciales, puedes eximir al campo de la indexación para pasar ese límite.

    Por ejemplo, en un caso práctico de IoT con una tasa alta de escritura, es posible que una colección de documentos con un campo de marca de tiempo se acerque al límite de 500 operaciones de escritura por segundo.

    Campos grandes de arreglo o de mapa

    Los campos grandes de arreglo o de mapa pueden acercarse al límite de 20,000 entradas de índice por documento. Si no realizas consultas basadas en un campo grande de arreglo o de mapa, debes excluir el campo de la indexación.