This page describes how to manage your indexes. To learn more
about indexes, see [Indexes overview](https://firebase.google.com/docs/firestore/enterprise/index-overview.md.txt).

## Before you begin

Before you can create an index in Cloud Firestore, make sure that you are assigned any of the following roles:

- `roles/datastore.owner`
- `roles/datastore.indexAdmin`
- `roles/editor`
- `roles/owner`

To grant a role, see [Grant a single role](https://cloud.google.com/iam/docs/granting-changing-revoking-access#single-role).
For more information about Cloud Firestore roles and associated permissions, see [Predefined roles](https://firebase.google.com/docs/firestore/enterprise/security/iam.md.txt).

If you have defined custom roles, assign all of the following permissions to create indexes:

- `datastore.indexes.create`
- `datastore.indexes.delete`
- `datastore.indexes.get`
- `datastore.indexes.list`
- `datastore.indexes.update`

## Create an index

To create an index, complete the following steps:

##### MongoDB API

Use the [`createIndex()`](https://www.mongodb.com/docs/manual/reference/method/db.collection.createIndex/) method to create an index. For example:

-

  ```bash
    db.restaurants.createIndex({"cuisine" : 1})
    
  ```
-

  ```bash
    db.restaurants.createIndex({"cuisine" : 1}, {sparse: true})
    
  ```
- Index creation with `db.runCommand()` is also supported with at most one index.

  ```bash
    db.runCommand({"createIndexes":"restaurant", "indexes": [{"key": {"cuisine":1}, "name": "cuisine_index"}]})
    
  ```

Note the following limitations:

- You can create only one index per request. `db.collection.createIndexes()` is not supported.
- [Audit logs](https://firebase.google.com/docs/firestore/enterprise/audit-logging.md.txt) for index creation with the MongoDB API use the method name `google.firestore.admin.v1.FirestoreAdmin.CreateIndex`.
- For supported index options, see [indexes and index properties](https://firebase.google.com/docs/firestore/enterprise/supported-features-80.md.txt#indexes_and_index_properties).

##### Firebase console

1. In the Firebase console, go to the **Firestore Database** page.

   [Go to Firestore Database](https://console.firebase.google.com/project/_/firestore/databases/-default-/data/)
2. Select a database from the list of databases.
3. In the **Indexes** tab, click **Create Index**.
4. Enter a **Collection ID**.
5. Add one or more field paths and select an index option for each.
6. Select a field presence option, either non-sparse or sparse.
7. Optionally, you can set the [multikey index](https://firebase.google.com/docs/firestore/enterprise/index-overview.md.txt#multikey) option.
8. Click **Create**.
9. Your new index is displayed in the list of indexes and Cloud Firestore begins creating your index. When your index is created, you will see a green check mark next to the index. If index is not created, see [Index building errors](https://firebase.google.com/docs/firestore/enterprise/index-overview.md.txt#index-building-errors) for possible causes.

##### gcloud CLI

To create an index, use the
[`gcloud firestore indexes composite create`](https://cloud.google.com/sdk/gcloud/reference/firestore/indexes/composite/create)
command. Set `api-scope` to `mongodb-compatible-api`.

```
gcloud firestore indexes composite create \
--database='DATABASE_ID' \
--collection-group=COLLECTION \
--field-config=FIELD_CONFIGURATION \
--query-scope=collection-group \
--density=dense \
--api-scope=mongodb-compatible-api
```

Replace the following:

- <var translate="no">DATABASE_ID</var>: a database ID.
- <var translate="no">COLLECTION</var>: a collection name.
- <var translate="no">FIELD_CONFIGURATION</var>: a field configuration. For each field, add `--field-config=field-path=`. For example:

  ```
      --field-config=field-path=user-id,order=descending \
      --field-config=field-path=score,order=descending
      
  ```

  For more information about configuring these fields, see [`--field-config`](https://cloud.google.com/sdk/gcloud/reference/firestore/indexes/composite/create#--field-config).

To create a sparse index, set `--density=sparse-any`.

To create a multikey index, add the `--multikey` flag.

To create a unique index, add the `--unique` flag.

##### Terraform

Use the
[`google_firestore_index`](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/firestore_index)
resource and set `api_scope` to `MONGODB_COMPATIBLE_API` and `query_scope` to `COLLECTION_GROUP`.

```terraform
resource "google_firestore_index" "index" {
  database    = "DATABASE_ID"
  collection  = "COLLECTION"
  api_scope   = "MONGODB_COMPATIBLE_API"
  query_scope = "COLLECTION_GROUP"

  // You can include multiple field blocks
  fields {
    field_path = "FIELD_PATH"
    order      = "ORDER"
  }

  // Optional
  multikey = true
  density  = "DENSITY"
}
```

Replace the following:

- <var translate="no">DATABASE_ID</var>: The database ID for your chosen database
- <var translate="no">COLLECTION</var>: The name of the collection to index
- <var translate="no">FIELD_PATH</var>: The name of the field to index
- <var translate="no">ORDER</var>: One of `ASCENDING` or `DESCENDING`
- <var translate="no">DENSITY</var>: One of `SPARSE_ANY` or `DENSE`

## Create a text index

Create a text index if you want to perform a text search for specific
strings within a collection.

To create a text index for your collection, complete the following steps:

### MongoDB API

Use the
[`createIndex()`](https://www.mongodb.com/docs/manual/reference/method/db.collection.createIndex/)
method to create a text index.
In the following example, when a document is written to the `cities`
collection with the `country`, or `food` fields populated,
these fields are indexed for searching purposes.

```bash
db.cities.createIndex({"country": "text", "food": "text"})
```

A field must be a string or an array of strings to be indexed.
Array indexes are not search-indexed. As a result, indexing `a.1.b` will index
`something` in `{a: {1: {b: something}}}`, but not in
`{a: [one, {b: something}]}`.

You can also create indexes with `db.runCommand()`. You can have only one
text index per collection, but you can create multiple indexes of different
types in one `db.runCommand()`. The following example uses `db.runCommand()`
to create a text index:

```bash
db.runCommand({
  createIndexes: "cities",
  indexes: [
    {
      key: { "country": "text", "food": "text" },
      name: "country_text_food_text"
    }
  ]
})
```

### Specify a default language

You can also optionally specify a default language, or a field path in your
document that will contain the default language.

In the following example, `myLanguageField`
is specified as the `language_override`. When a document in the `cities`
collection contains a field named `myLanguageField`, the value of that field
is used to determine the language for indexing the `country` field for that
specific document. That value overrides the default language of `french`.

```bash
db.cities.createIndex({"country": "text"}, {"default_language": "french", "language_override": "myLanguageField"})
```

- You can enter a language as either its long form name (`english`) or its two-letter ISO language code (`en`).
- If the default language is left unset, then Cloud Firestore defaults to English.
- The language override field must be a top-level field. If left unset, the language override field defaults to `language`.
- If you set the default language to the `null` character, then Cloud Firestore doesn't use any field as a language override.

#### Expand for a list of supported languages

| Language Code | Language Name |
|---|---|
| "und" | Autodetect |
| "af" | Afrikaans |
| "ak" | Akan |
| "sq" | Albanian |
| "am" | Amharic |
| "ar" | Arabic |
| "hy" | Armenian |
| "az" | Azerbaijani |
| "eu" | Basque |
| "be" | Belarusian |
| "bn" | Bangla |
| "bs" | Bosnian |
| "bg" | Bulgarian |
| "my" | Burmese |
| "ca" | Catalan |
| "ceb" | Cebuano |
| "chr" | Cherokee |
| "zh" | Chinese |
| "zh-Hant" | Chinese_Traditional |
| "hr" | Croatian |
| "cs" | Czech |
| "da" | Danish |
| "nl" | Dutch |
| "en" | English |
| "eo" | Esperanto |
| "et" | Estonian |
| "fil" | Filipino |
| "fi" | Finnish |
| "fr" | French |
| "gl" | Galician |
| "ka" | Georgian |
| "de" | German |
| "el" | Greek |
| "gu" | Gujarati |
| "ht" | Haitian_Creole |
| "ha" | Hausa |
| "haw" | Hawaiian |
| "iw" | Hebrew |
| "hi" | Hindi |
| "hmn" | Hmong |
| "hu" | Hungarian |
| "is" | Icelandic |
| "ig" | Igbo |
| "id" | Indonesian |
| "ga" | Irish |
| "it" | Italian |
| "ja" | Japanese |
| "jv" | Javanese |
| "kn" | Kannada |
| "kk" | Kazakh |
| "km" | Khmer |
| "ko" | Korean |
| "lo" | Lao |
| "la" | Latin |
| "lv" | Latvian |
| "lt" | Lithuanian |
| "lb" | Luxembourgish |
| "mk" | Macedonian |
| "mg" | Malagasy |
| "ms" | Malay |
| "ml" | Malayalam |
| "mt" | Maltese |
| "mi" | Maori |
| "mr" | Marathi |
| "mfe" | Morisyen |
| "mn" | Mongolian |
| "sr-ME" | Serbian_Montenegro |
| "ne" | Nepali |
| "no" | Norwegian |
| "ny" | Nyanja |
| "or" | Odia |
| "fa" | Persian |
| "pl" | Polish |
| "pt-BR" | Portuguese_Brazil |
| "pt-PT" | Portuguese_Portugal |
| "pa" | Punjabi |
| "ro" | Romanian |
| "ru" | Russian |
| "gd" | Scottish Gaelic |
| "sr" | Serbian |
| "st" | Southern Sotho |
| "si" | Sinhala |
| "sk" | Slovak |
| "sl" | Slovenian |
| "so" | Somali |
| "es" | Spanish |
| "su" | Sundanese |
| "sw" | Swahili |
| "sv" | Swedish |
| "tg" | Tajik |
| "ta" | Tamil |
| "te" | Telugu |
| "th" | Thai |
| "tr" | Turkish |
| "uk" | Ukrainian |
| "ur" | Urdu |
| "uz" | Uzbek |
| "vi" | Vietnamese |
| "cy" | Welsh |
| "yi" | Yiddish |
| "yo" | Yoruba |
| "zu" | Zulu |

### Partition a text index

You can also partition your index using a field so that you can filter queries
by a specific field value. This configuration lets you run more peformant
queries if you always need a specific field filtered in the index you're
querying.

To create an index with a partition,
configure the `firestoreOptions` field as follows:

```bash
db.runCommand({
  createIndexes: "cities",
  indexes: [
    {
      key: { "country": "text", "food": "text"},
      name: "country_text_food_text"
      firestoreOptions: {"customPartitionFields": ["PARTITIONED_FIELD"]
    }
  ]
})
```

Where:

- `PARTITIONED_FIELD` is the name of the field used for
  the partition. This value must be a string and must refer to a top-level
  field. When you run a query against a partitioned index, you can
  filter the results based on a value of this field. For example,
  you could partition your index using `city`. If a `city` field is defined
  in your text index, then users can query against a specific city.

  The partition must be only one field. If you partition an index, then you can
  run only queries where the partitioned field is specified.

**Limitations**

- You can create only one index per request.
- [Audit logs](https://firebase.google.com/docs/firestore/enterprise/audit-logging.md.txt) for index creation with the MongoDB API use the method name `google.firestore.admin.v1.FirestoreAdmin.CreateIndex`.
- For supported index options, see [indexes and index
  properties](https://firebase.google.com/docs/firestore/enterprise/supported-features-80#indexes_and_index_properties).

### Firebase console

1. In the **Firebase console** , go to the **Firestore Database** page.

   [Go to Firestore Database](https://console.firebase.google.com/project/_/firestore/databases/-default-/data/)
2. Select a database from the list of databases.

3. In the **Indexes** tab, click **Create Index**.

4. Enter a **Collection ID**.

5. Add one or more field paths and select an index option for each.

6. Click **Create**.

7. Your new index is displayed in the list of indexes and
   MongoDB compatible operations begins creating your index. When your index is
   created, you will see a green check mark next to the index. If index is not
   created, see [Index building
   errors](https://firebase.google.com/docs/firestore/enterprise/index-overview#index-building-errors) for possible
   causes.

### gcloud CLI

To create a text index, use the
[`gcloud firestore indexes composite create`](https://cloud.google.com/sdk/gcloud/reference/firestore/indexes/composite/create)
command. Set `--api-scope` to `mongodb-compatible-api`.

```
gcloud firestore indexes composite create \
  --database='DATABASE_ID' \
  --collection-group=COLLECTION_GROUP \
  --field-config=field-path=FIELD_NAME,search-config='{"text-spec": {"index-specs": [{"index-type": "tokenized", "match-type": "match-globally"}]}}' \
  --api-scope=mongodb-compatible-api \
  --search-index-options=text-language=en \
  --async
```

Replace the following:

- <var translate="no">DATABASE_ID</var>: a database ID.
- <var translate="no">COLLECTION_GROUP</var>: the ID of the collection to index.
- <var translate="no">FIELD_NAME</var>: the name of the field to index.

The `--async` flag runs the index creation operation in the background.

## Create a 2dsphere index

Create a 2dsphere index to perform geospatial queries and search for
documents that exist within a certain range from a specific longitude and
latitude.

To create a 2dsphere index for your collection, complete the
following steps:

### MongoDB API

Use the
[`createIndex()`](https://www.mongodb.com/docs/manual/reference/method/db.collection.createIndex/)
method to create an index. For example:

```bash
db.restaurants.createIndex({"location" : "2dsphere", "region": "2dsphere"})
```

Index creation with `db.runCommand()` is also supported with at most one
index:

```bash
db.runCommand({
  createIndexes: "restaurants",
  indexes: [
    {
      key: { "location": "2dsphere", "region": "2dsphere" },
      name: "location_2dsphere_region_2dsphere"
    }
  ]
})
```

### Partition a 2dsphere index

You can also partition your index using a field so that you can filter queries
by a specific field value. This configuration lets you run more peformant
queries if you always need a specific field filtered in the index you're
querying.

To create an index with a partition,
configure the `firestoreOptions` field as follows:

```bash
db.runCommand({
  createIndexes: "restaurants",
  indexes: [
    {
      key: { "location": "2dsphere", "region": "2dsphere" },
      name: "location_2dsphere_region_2dsphere"
      firestoreOptions: {"customPartitionFields": ["PARTITIONED_FIELD"]
    }
  ]
})
```

Where:

- `PARTITIONED_FIELD` is the name of the field used for
  the partition. When you run a query against a partitioned index, you can
  filter the results based on a value of this field. For example, if your
  index has a `region` field for regional locations, you could partition
  your index using `region` so that users can query against restaurants in their
  region.

  If you partition an index, then you can only run queries where the partitioned
  field is specified.

**Limitations**

- You can create only one index per request.
- [Audit logs](https://firebase.google.com/docs/firestore/enterprise/audit-logging.md.txt) for index creation with the MongoDB API use the method name `google.firestore.admin.v1.FirestoreAdmin.CreateIndex`.
- For supported index options, see [indexes and index
  properties](https://firebase.google.com/docs/firestore/enterprise/supported-features-80#indexes_and_index_properties).

### Firebase console

1. In the **Firebase console** , go to the **Firestore Database** page.

   [Go to Firestore Database](https://console.firebase.google.com/project/_/firestore/databases/-default-/data/)
2. Select a database from the list of databases.

3. In the **Indexes** tab, click **Create Index**.

4. Enter a **Collection ID**.

5. Add one or more field paths and select an index option for each.

6. Click **Create**.

7. Your new index is displayed in the list of indexes and
   MongoDB compatible operations begins creating your index. When your index is
   created, you will see a green check mark next to the index. If index is not
   created, see [Index building
   errors](https://firebase.google.com/docs/firestore/enterprise/index-overview#index-building-errors) for possible
   causes.

### gcloud CLI

To create a 2dsphere index, use the
[`gcloud firestore indexes composite create`](https://cloud.google.com/sdk/gcloud/reference/firestore/indexes/composite/create)
command. Set `--api-scope` to `mongodb-compatible-api`.

```
gcloud firestore indexes composite create \
  --database='DATABASE_ID' \
  --collection-group=COLLECTION_GROUP \
  --field-config=field-path=FIELD_NAME,search-config='{"geo-spec": {}}' \
  --api-scope=mongodb-compatible-api \
  --async
```

Replace the following:

- <var translate="no">DATABASE_ID</var>: a database ID.
- <var translate="no">COLLECTION_GROUP</var>: the ID of the collection to index.
- <var translate="no">FIELD_NAME</var>: the name of the field to index.

The `--async` flag runs the index creation operation in the background.

## Delete an index

To delete an index, complete the following steps:

> [!NOTE]
> **Note:** Dropping an entire collection using the `drop()` command also deletes all associated indexes for that collection.

##### MongoDB API

Use the [`dropIndex()`](https://www.mongodb.com/docs/manual/reference/method/db.collection.dropIndex/) method to delete an index. For example:

**Delete an index using index name**

```bash
db.restaurants.dropIndex("cuisine_index")
```

**Delete an index using index definition**

```bash
db.restaurants.dropIndex({"cuisine" : 1})
```

##### Firebase console

1. In the Firebase console, go to the **Firestore Database** page.

   [Go to Firestore Database](https://console.firebase.google.com/project/_/firestore/databases/-default-/data/)
2. Select a database from the list of databases.
3. Click the **Indexes** tab.
4. In the list of indexes, choose **Delete** from the **More** button for the index you want to delete.
5. Click **Delete Index**.

##### gcloud CLI

1. To find the name of the index, use the [`gcloud firestore indexes composite list`](https://cloud.google.com/sdk/gcloud/reference/firestore/indexes/composite/list) command.

   ```
   gcloud firestore indexes composite list \
   --database='DATABASE_ID'
   ```

   Replace <var translate="no">DATABASE_ID</var> with the database ID.
2. To delete the index, use the
   [`gcloud firestore indexes composite delete`](https://cloud.google.com/sdk/gcloud/reference/firestore/indexes/composite/delete)
   command.

   ```
   gcloud firestore indexes composite delete INDEX_NAME \
   --database='DATABASE_ID'
   ```

   Replace the following:
   - <var translate="no">INDEX_NAME</var>: the name of an index
   - <var translate="no">DATABASE_ID</var>: a database ID

## Index build time

To build an index, Cloud Firestore must create the index and then
backfill the index entries with existing data. The time required to create an
index is determined by the following:

- The minimum build time for an index is a few minutes, even for an empty database.

- The time required to backfill index entries depends on how much existing data
  belongs in the new index. The more field values that match the index definition,
  the longer it takes to backfill the index entries.

### Manage long-running operations

Index builds are *long-running operations*. The following sections describe
how to work with long-running operations for indexes.

> [!IMPORTANT]
> **Key Term:** Cloud Firestore supports several administrative operations that can take a long time to complete. These operations are called ***long-running
> operations*** . Cloud Firestore includes features to execute and manage long- running operations. Supported long-running operations include index builds and export operations.

After you start to create an index, Cloud Firestore assigns
the operation a unique name. Operation names are prefixed with `projects/PROJECT_ID/databases/DATABASE_ID/operations/`,
for example:

```
projects/PROJECT_ID/databases/DATABASE_ID/operations/ASA1MTAwNDQxNAgadGx1YWZlZAcSeWx0aGdpbi1zYm9qLW5pbWRhEgopEg
```

You can omit the prefix when specifying an operation name for
the `describe` command.

### List all long-running operations

To list long-running operations, use the
[`gcloud firestore operations list`](https://cloud.google.com/sdk/gcloud/reference/firestore/operations/list)
command. This command lists ongoing and recently completed operations.
Operations are listed for a few days after completion:

```
gcloud firestore operations list
```

### Check operation status

Instead of listing all long-running operations, you can list the details of
a single operation:

<br />

```
gcloud firestore operations describe operation-name
```

<br />

### Estimating the completion time

As your operation runs, see the value of the [`state` field](https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.admin.v1#state)
for the overall status of the operation.

A request for the status of a long-running operation also returns the metrics
`workEstimated` and `workCompleted`. `workEstimated` shows the estimated total
number of documents an
operation will process. `workCompleted`
shows the number of documents processed so far. After the operation completes,
`workCompleted` reflects the total number of documents that were
actually processed, which might be different than the value of `workEstimated`.

To estimate an operation's progress, divide `workCompleted` by `workEstimated`.

> [!NOTE]
> **Note:** The estimate might be inaccurate because it depends on delayed statistics collection.

The following is an example of the progress of creating an index:

```
{
  "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"
        }
       },
    },
    ...
```

When an operation completes, the operation description will contain
[`"done": true`](https://cloud.google.com/firestore/docs/reference/rpc/google.longrunning#operation). See the value of the [`state` field](https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.admin.v1#state) for
the result of the operation. If the `done` field is not set in the response,
then the operation has not completed.