= Indexes :description: Keep filters and sorts fast as a collection grows: create, inspect and delete MongoDB indexes from the console, with the unique, TTL and full-text patterns. :keywords: MongoDB index, unique index, TTL index, text index, compound index, query performance :group: Your data :order: 20 Without an index, a filter scans every document in the collection. That is fine for a thousand documents and slow for a million. An index keeps the values of a field sorted, so a filter or a sort on that field jumps straight to the documents it needs. Indexes also give you two rules for free: a **unique** index refuses duplicates, and a **TTL** index deletes documents after a time. Every collection has an index on `_id` already. The rest you add under **Indexes**. image::/assets/docs-images/indexes.png[The Indexes page: each collection with the number of indexes it has, ready to expand] == Create an index . Open **Indexes** and expand the collection. . Click **New Index** and give it a name, such as `email-unique` or `category-price`. . Type the **Keys**: which fields, and `1` for ascending, `-1` for descending, or `"text"` for full-text search. . Add **Options** if you need them, and **Save**. Both fields are JSON, checked as you type. Building an index on a collection that already has data takes a moment. [cols="1,3"] |=== | Option | What it does | `unique` | Refuses a document whose value already exists in another. Fails with `406` if duplicates exist when you create it: clean them up first. | `sparse` | Indexes only documents that have the field. With `unique`, documents without the field do not count as duplicates. | `expireAfterSeconds` | Makes it a TTL index: a document is deleted that many seconds after the date in the indexed field. `0` means at that date. The check runs about once a minute. | `name` | The index's name. The console sets it from the field you type. |=== == The patterns that cover most apps [cols="2,3"] |=== | Keys and options | Use it for | `{"status": 1}` | A filter on one field, such as `?filter={"status": "pending"}`. | `{"category": 1, "price": -1}` | A filter on the first field and a sort on the second, such as `?filter={"category": "shoes"}&sort={"price": -1}`. The index serves any query on a prefix of its fields. | `{"email": 1}` with `{"unique": true}` | No two documents with the same email. | `{"taxId": 1}` with `{"unique": true, "sparse": true}` | Unique when present, optional otherwise. | `{"expiresAt": 1}` with `{"expireAfterSeconds": 0}` | Sessions, tokens, logs: gone when `expiresAt` passes. The field must be a date. | `{"title": "text", "body": "text"}` | Keyword search with `?filter={"$text": {"$search": "running shoes"}}`. One text index per collection; put every field you want searched in it. |=== == Change or delete an index An index cannot be edited. To change one, delete it and create it again with the new definition. The **Delete** action asks for confirmation and is immediate; until you create a replacement, queries that used it scan the collection. The `_id` index cannot be deleted. == From a script [cols="2,3"] |=== | Operation | API | List | `GET //_indexes` | Create | `PUT //_indexes/` with `{ "keys": {...}, "ops": {...} }` | Delete | `DELETE //_indexes/` |=== A `406 Not Acceptable` on create means the definition was refused: duplicates under a unique index, or a name already used by a different index. The response says which. With xref:cli.adoc[`rhc`], indexes are part of the setup file and are created with the rest of the service. == Related pages * xref:managing-data.adoc[Collections and documents]: the filters and sorts the indexes speed up. * xref:schemas.adoc[Schemas]: rules on one document. A unique index is a rule across documents. * xref:constraints.adoc[Constraints]: rules across the whole collection that an index cannot express.