Gestionar índices

Firestore asegura el rendimiento de las consultas al requerir un índice para cada consulta. Los índices necesarios para las consultas más básicas se crean automáticamente. Mientras usas y pruebas tu aplicación, Cloud Firestore genera mensajes de error que te ayudan a crear los índices adicionales que necesita tu aplicación. En esta página se describe cómo gestionar tus índices de campo único, compuestos y [vector][vector].

Crear un índice que falta a través de un mensaje de error

Si intentas hacer una consulta compuesta con una cláusula de intervalo que no se corresponda con un índice, recibirás un error. El mensaje de error incluye un enlace directo para crear el índice que falta en la consola de Firebase.

Sigue el enlace generado a la consola de Firebase, revisa la información que se ha rellenado automáticamente y haz clic en Crear.

Si se necesita un índice vectorial, el mensaje de error incluirá un comando de la interfaz de línea de comandos de Google Cloud para crear el índice vectorial que falta. Ejecuta el comando para crear el índice que falta.

Roles y permisos

Para poder crear un índice en Firestore, debes tener asignado uno de los siguientes roles:

  • roles/datastore.owner
  • roles/datastore.indexAdmin
  • roles/editor
  • roles/owner

Si has definido roles personalizados, asigna todos los permisos siguientes para crear índices:

  • datastore.indexes.create
  • datastore.indexes.delete
  • datastore.indexes.get
  • datastore.indexes.list
  • datastore.indexes.update

Usar la consola de Google Cloud Platform

Desde la consola de Google Cloud Platform, puede gestionar las exenciones de indexación de un solo campo y los índices compuestos.

Crear un índice compuesto

Para crear manualmente un índice compuesto desde la consola de GCP, sigue estos pasos:

  1. En la Google Cloud consola, ve a la página Bases de datos.

    Ir a Bases de datos

  2. Seleccione la base de datos que necesite de la lista de bases de datos.

  3. En el menú de navegación, haga clic en Índices y, a continuación, en la pestaña Compuesto.

  4. Haz clic en Crear índice.

  5. Introduce un ID de colección. Añade los nombres de los campos que quieras indexar y un modo de indexación para cada campo. Haz clic en Guardar índice.

El nuevo índice aparecerá en la lista de índices compuestos y Firestore empezará a crearlo. Cuando se haya creado el índice, verás una marca de verificación verde junto a él.

Eliminar un índice compuesto

Para eliminar un índice compuesto, sigue estos pasos:

  1. En la Google Cloud consola, ve a la página Bases de datos.

    Ir a Bases de datos

  2. Seleccione la base de datos que necesite de la lista de bases de datos.

  3. En el menú de navegación, haga clic en Índices y, a continuación, en la pestaña Compuesto.

  4. En la lista de índices compuestos, haz clic en el botón Más del índice que quieras eliminar. Haz clic en Eliminar.

  5. Confirma que quieres eliminar este índice haciendo clic en Eliminar índice en la alerta.

Añadir una exención de índice de campo único

Las exenciones de índices de un solo campo te permiten anular la configuración de índices automática de campos concretos de una colección. Puede añadir una exención de un solo campo desde la consola:

  1. En la Google Cloud consola, ve a la página Bases de datos.

    Ir a Bases de datos

  2. Seleccione la base de datos que necesite de la lista de bases de datos.

  3. En el menú de navegación, haga clic en Índices y, a continuación, en la pestaña Campo único.

  4. Haga clic en Añadir exención.

  5. Introduce un ID de colección y una ruta de campo.

  6. Selecciona la nueva configuración de indexación de este campo. Habilita o inhabilita los índices de un solo campo ascendentes, descendentes y array-contains que se actualizan automáticamente para este campo.

  7. Haz clic en Guardar exención.

Añadir una exención a nivel de colección

Para definir una exención de índice de campo único que se aplique a todos los campos de un ID de colección, sigue estos pasos:

  1. Haga clic en Añadir exención.
  2. Introduzca un ID de colección para el grupo de colecciones y defina Ruta del campo como *.

    Elige el campo que quieras excluir

  3. Selecciona las exenciones de indexación que quieras aplicar a todos los campos del grupo de colecciones.

  4. Haz clic en Guardar exención.

Eliminar una exención de índice de campo único

Para eliminar una exención de índice de un solo campo, siga estos pasos:

  1. En la Google Cloud consola, ve a la página Bases de datos.

    Ir a Bases de datos

  2. Seleccione la base de datos que necesite de la lista de bases de datos.

  3. En el menú de navegación, haga clic en Índices y, a continuación, en la pestaña Campo único.

  4. En la lista de exenciones de índice de un solo campo, haz clic en el botón Más de la exención que quieras eliminar. Haz clic en Eliminar.

  5. Confirma que quieres eliminar esta exención haciendo clic en Eliminar en la alerta.

Cuando eliminas una exención de un solo campo, el campo o subcampo especificado utilizará la configuración de indexación heredada. Los campos de los documentos vuelven a la configuración automática de índices de tu base de datos. Los subcampos de un mapa heredan las exenciones de los campos principales antes de heredar la configuración de indexación automática.

Usar la CLI de Firebase

También puedes desplegar índices con la CLI de Firebase. Para empezar, ejecuta firebase init firestore en el directorio de tu proyecto. Durante la configuración, la CLI de Firebase genera un archivo JSON con los índices predeterminados en el formato correcto. Edita el archivo para añadir más índices e impleméntalo con el comando firebase deploy.

Para desplegar solo los índices y las reglas de Firestore, añade la marca --only firestore.

Si editas los índices con la consola de Firebase, asegúrate de actualizar también el archivo de índices local. Consulta la referencia de definición de índice JSON.

Usar Terraform

Crear índices en la base de datos

Las bases de datos de Firestore pueden incluir índices de campo único y compuestos. Puedes editar el archivo de configuración de Terraform para crear un índice en tu base de datos. Los índices de un solo campo y los compuestos usan tipos de recursos de Terraform distintos (google_firestore_index y google_firestore_field).

Se admiten los índices de Firestore en modo nativo y en modo Datastore.

Índice de un solo campo

El siguiente archivo de configuración de Terraform de ejemplo crea un índice de un solo campo en el campo name de la colección chatrooms:

firestore.tf

resource "random_id" "variable"{
  byte_length = 8
}

resource "google_firestore_field" "single-index" {
  project = "project-id"
  database = "database-id"
  collection = "chatrooms_${random_id.variable.hex}"
  field = "name"

  index_config {
    indexes {
        order = "ASCENDING"
        query_scope = "COLLECTION_GROUP"
    }
    indexes {
        array_config = "CONTAINS"
    }
  }

  ttl_config {}
}
  • Sustituye project-id por el ID del proyecto. Los IDs de proyecto deben ser únicos.
  • Sustituye database-id por el ID de tu base de datos.

Índice compuesto

El siguiente archivo de configuración de Terraform de ejemplo crea un índice compuesto para una combinación del campo name y el campo description de la colección chatrooms:

firestore.tf

resource "google_firestore_index" "composite-index" {
  project = "project-id"
  database = "database-id"

  collection = "chatrooms"

  fields {
    field_path = "name"
    order      = "ASCENDING"
  }

  fields {
    field_path = "description"
    order      = "DESCENDING"
  }

}
  • Sustituye project-id por el ID del proyecto. Los IDs de proyecto deben ser únicos.
  • Sustituye database-id por el ID de tu base de datos.

Índice de vectores

El siguiente archivo de configuración de Terraform crea un índice vectorial en el campo embedding de la colección chatrooms:

firestore.tf

resource "google_firestore_index" "vector-index" {
  project = "project-id"
  database = "database-id"
  collection = "chatrooms"

  fields {
    field_path = "__name__"
    order = "ASCENDING"
  }

  fields {
    field_path = "embedding"
    vector_config {
      dimension = 128
      flat {}
    }
  }
}
  • Sustituye project-id por el ID del proyecto. Los IDs de proyecto deben ser únicos.
  • Sustituye database-id por el ID de tu base de datos.

Índices del modo Datastore

También puedes crear índices del modo Datastore con Terraform.

datastore.tf

resource "google_firestore_index" "datastore-mode-index" {
  project = "project-id"
  database = "database-id"

  collection = "chatrooms"

  fields {
    field_path = "name"
    order      = "ASCENDING"
  }

  fields {
    field_path = "description"
    order      = "DESCENDING"
  }

  query_scope = "COLLECTION_GROUP"
  api_scope   = "DATASTORE_MODE_API"
}
Migrar desde google_datastore_index

El recurso google_datastore_index está obsoleto y no estará disponible en la versión 6.0.0 y posteriores de terraform-provider-google.

Si antes usabas el recurso google_datastore_index, puedes migrar a google_firestore_index. Para migrar, haz lo siguiente:

  1. Escribe un recurso google_firestore_index equivalente.
  2. Importa tu índice del modo Datastore en el nuevo recurso.
  3. Quita las referencias al recurso google_datastore_index antiguo.
  4. Elimina el recurso google_datastore_index antiguo del estado de Terraform.
  5. Ejecutando terraform apply para aplicar los cambios.

A continuación, se ofrecen instrucciones más detalladas:

  1. Escribe un google_firestore_index de sustitución basado en tu recurso google_datastore_index. Consulta los cambios necesarios más abajo.
  2. Determina la ruta de recurso de Firestore de tu índice:

    export INDEX_RESOURCE_PATH=$(echo '"projects/${google_datastore_index.datastore-index-resource-name.project}/databases/(default)/collectionGroups/${google_datastore_index.datastore-index-resource-name.kind}/indexes/${google_datastore_index.datastore-index-resource-name.index_id}"' | terraform console | tr -d '"')
    

    Sustituye datastore-index-resource-name por el nombre de Terraform del recurso que ya tienes.

  3. Importa tu índice del modo Datastore a la google_firestore_index que has creado anteriormente:

    terraform import google_firestore_index.firestore-index-resource-name $INDEX_RESOURCE_PATH
    

    Sustituye firestore-index-resource-name por el nombre de Terraform del recurso que ya tienes.

    Para obtener más información sobre cómo importar recursos de índice de Firestore, consulta la documentación de referencia de google_firestore_index.

  4. Elimina el recurso google_datastore_index de tu archivo de configuración de Terraform.
  5. Elimina el recurso google_datastore_index del estado de Terraform:

    terraform state rm google_datastore_index.datastore-index-resource-name
    

    Para obtener más información sobre cómo quitar recursos, consulta la página de Terraform sobre cómo quitar recursos.

  6. Ejecuta terraform plan. Verifica el resultado para confirmar que no estás creando ni destruyendo ningún recurso.

    Inspecciona el resultado para asegurarte de que la importación se ha completado correctamente. Si la salida muestra algún campo que cambia, asegúrate de que esos cambios son intencionados. Si el resultado incluye una línea similar a la siguiente:

    google_firestore_index.firestore-index-resource-name must be replaced
    

    A continuación, inspecciona el archivo de configuración de Terraform para ver si hay algún error.

  7. Cuando estés conforme con el resultado del plan de Terraform, ejecuta lo siguiente:

    terraform apply
    

  8. Traducir tu índice

    Para traducir un recurso google_datastore_index al recurso google_firestore_index equivalente, cópialo y haz los siguientes cambios:

    • Reemplaza google_datastore_index por google_firestore_index.
    • Sustituye el nombre del argumento kind por collection, pero mantén el mismo valor del argumento.
    • Sustituye el nombre del argumento ancestor por query_scope. Sustituye el valor del argumento ALL_ANCESTORS por COLLECTION_RECURSIVE y cualquier otro valor por COLLECTION_GROUP. Si no hay ningún argumento ancestor, añade un argumento query_scope con el valor COLLECTION_GROUP.
    • Añade el argumento api_scope con el valor DATASTORE_MODE_API.
    • Sustituye cada instancia de properties por la instancia correspondiente de fields. Sustituye cada instancia de name por field_path y cada instancia de direction por order.

    Por ejemplo, considera este recurso google_datastore_index:

    datastore.tf

    resource "google_datastore_index" "legacy" {
      kind = "foo"
    
      properties {
        name = "property_a"
        direction = "ASCENDING"
      }
    
      properties {
        name = "property_b"
        direction = "ASCENDING"
      }
    }
    

    El recurso google_firestore_index equivalente sería el siguiente:

    resource "google_firestore_index" "new" {
      // note: defaults to the provider project
      project = project
    
      // note: defaults to the (default) database
      database = "(default)"
    
      collection = "foo"
    
      api_scope = "DATASTORE_MODE_API"
    
      // since there was no "ancestor" property set above, use COLLECTION_GROUP here
      query_scope = "COLLECTION_GROUP"
    
      fields {
        field_path = "property_a"
        order  = "ASCENDING"
      }
    
      fields {
        field_path = "property_b"
        order = "ASCENDING"
      }
    }
    

    Tiempo de compilación del índice

    Para crear un índice, Firestore debe configurarlo y, a continuación, rellenarlo con los datos que ya tenga. El tiempo de compilación del índice es la suma del tiempo de configuración y el tiempo de relleno:

    • Configurar un índice lleva unos minutos. El tiempo mínimo de compilación de un índice es de unos minutos, incluso en el caso de una base de datos vacía.

    • El tiempo de reposición depende de la cantidad de datos que haya en el nuevo índice. Cuantos más valores de campo coincidan con la definición del índice, más tiempo se tardará en rellenar el índice.

    Las compilaciones de índices son operaciones de larga duración.

    Después de iniciar una compilación de índice, Firestore asigna un nombre único a la operación. Los nombres de las operaciones van precedidos de projects/[PROJECT_ID]/databases/(default)/operations/, por ejemplo:

    projects/project-id/databases/(default)/operations/ASA1MTAwNDQxNAgadGx1YWZlZAcSeWx0aGdpbi1zYm9qLW5pbWRhEgopEg
    

    Sin embargo, puede omitir el prefijo al especificar un nombre de operación para el comando describe.

    Mostrar todas las operaciones de larga duración

    Para enumerar las operaciones de larga duración, usa el comando gcloud firestore operations list. Este comando muestra las operaciones en curso y las que se han completado recientemente. Las operaciones se muestran durante unos días después de completarse:

    gcloud firestore operations list
    

    Comprobar el estado de la operación

    En lugar de enumerar todas las operaciones de larga duración, puedes consultar los detalles de una sola operación:

    gcloud firestore operations describe operation-name

    Estimar el tiempo de finalización

    Mientras se ejecuta la operación, consulta el valor del campo state para ver el estado general de la operación.

    Una solicitud del estado de una operación de larga duración también devuelve las métricas workEstimated y workCompleted. Estas métricas se devuelven para el número de documentos. workEstimated muestra el número total estimado de documentos que procesará una operación. workCompleted muestra el número de documentos procesados hasta el momento. Una vez completada la operación, workCompleted refleja el número total de documentos que se han procesado, que puede ser diferente del valor de workEstimated.

    Divide workCompleted entre workEstimated para obtener una estimación aproximada del progreso. Es posible que la estimación no sea precisa porque depende de la recogida de estadísticas con retraso.

    Por ejemplo, este es el estado del progreso de una compilación de índice:

    {
      "operations": [
        {
          "name": "projects/project-id/operations/AyAyMDBiM2U5NTgwZDAtZGIyYi0zYjc0LTIzYWEtZjg1ZGdWFmZWQHEjF0c2Flc3UtcmV4ZWRuaS1uaW1kYRUKSBI",
          "metadata": {
            "@type": "type.googleapis.com/google.firestore.admin.v1.IndexOperationMetadata",
            "common": {
              "operationType": "CREATE_INDEX",
              "startTime": "2020-06-23T16:52:25.697539Z",
              "state": "PROCESSING"
            },
            "progressDocuments": {
              "workCompleted": "219327",
              "workEstimated": "2198182"
            }
           },
        },
        ...
    

    Cuando se complete una operación, la descripción de la operación contendrá "done": true. Consulta el valor del campo state para ver el resultado de la operación. Si el campo done no se define en la respuesta, su valor será false. No dependas de la existencia del valor done para las operaciones en curso.

    Errores de creación de índices

    Es posible que se produzcan errores de compilación de índices al gestionar índices compuestos y exenciones de índices de un solo campo. Una operación de indexación puede fallar si Firestore detecta un problema con los datos que está indexando. Lo más habitual es que hayas alcanzado un límite de índice. Por ejemplo, es posible que la operación haya alcanzado el número máximo de entradas de índice por documento.

    Si no se puede crear el índice, verás el mensaje de error en la consola. Después de verificar que no has alcanzado ningún límite de índice, vuelve a intentar la operación de índice.