DocsHub
Indexes

Creating Indexes

Learn how to create single field, compound, and multikey indexes in MongoDB using createIndex.

Creating Indexes

Now that you understand what indexes are and why they matter, let's create them. MongoDB gives you one main method for this:

db.collection.createIndex({ field: type }, options)

The first argument is the index specification — which field to index and in what order. The second argument is optional index options — things like making the index unique or giving it a name.


Single Field Index

A single field index indexes one field. This is the most common type.

Syntax

db.collection.createIndex({ field: 1 })  // ascending
db.collection.createIndex({ field: -1 }) // descending

1 means ascending order — A to Z, 0 to 9. -1 means descending order — Z to A, 9 to 0.

For a single field index, ascending and descending perform the same for equality queries like { name: "Ali" }. The direction matters more for sorting and compound indexes.

Example — Index on student name

db.students.createIndex({ name: 1 })

Now this query uses the index instead of scanning all documents:

db.students.find({ name: "Ali Hassan" })

Example — Index on grade

db.students.createIndex({ grade: 1 })

Now filtering by grade is fast:

db.students.find({ grade: "10th" })

Example — Index on enrollmentDate

db.students.createIndex({ enrollmentDate: -1 })

Now sorting by most recently enrolled is fast:

db.students.find().sort({ enrollmentDate: -1 })

Unique Index

A unique index ensures no two documents in a collection can have the same value for a field. MongoDB will reject any insert or update that would create a duplicate.

// No two students can have the same email
db.students.createIndex({ email: 1 }, { unique: true })

Now if you try to insert two students with the same email:

db.students.insertOne({ name: "Ali Hassan", email: "ali@school.com" })
db.students.insertOne({ name: "Ali Ahmed", email: "ali@school.com" }) // ERROR

The second insert throws:

MongoServerError: E11000 duplicate key error — email: "ali@school.com"

The _id index is always unique — MongoDB enforces this automatically. For other fields like email or rollNumber, you create the unique index yourself.

Unique indexes are a great way to enforce data integrity at the database level. Even if your application code has a bug that tries to insert a duplicate, the database will reject it.


Compound Index

A compound index indexes multiple fields together in one index. It is more powerful than two separate single field indexes for queries that filter or sort by multiple fields.

Syntax

db.collection.createIndex({ field1: 1, field2: 1 })

Example — Index on grade and enrolled

db.students.createIndex({ grade: 1, enrolled: 1 })

This index makes the following query fast:

db.students.find({ grade: "10th", enrolled: true })

Field order matters

The order of fields in a compound index is important. An index on { grade: 1, enrolled: 1 } can support:

// Supported — uses the index
db.students.find({ grade: "10th" })
db.students.find({ grade: "10th", enrolled: true })
db.students.find({ grade: "10th" }).sort({ enrolled: 1 })

But it cannot efficiently support:

// Not supported — enrolled is not the leading field
db.students.find({ enrolled: true })

This is called the prefix rule — a compound index can be used for queries that use the leading fields of the index. A query on just enrolled cannot use the { grade: 1, enrolled: 1 } index because grade is the leading field and it is not in the filter.

Think of a compound index like a phone book sorted by last name then first name. You can quickly find everyone with the last name "Hassan" — or everyone named "Ali Hassan" — but you cannot quickly find everyone named "Ali" across all last names without reading the whole book.

Example — Index on grade, enrolled, and name for sorting

db.students.createIndex({ grade: 1, enrolled: 1, name: 1 })

This supports:

// Fast — uses all three fields
db.students
  .find({ grade: "10th", enrolled: true })
  .sort({ name: 1 })

Multikey Index

When you create an index on a field that contains an array, MongoDB automatically creates a multikey index. It indexes each element of the array separately so you can query by any value in the array.

Example — Index on subjects array

db.students.createIndex({ subjects: 1 })

MongoDB creates an index entry for each subject in every student's subjects array. So a student with subjects: ["Math", "Physics", "English"] gets three index entries — one for each subject.

Now this query is fast:

// Uses the multikey index
db.students.find({ subjects: "Math" })

You do not need to do anything special to create a multikey index — MongoDB detects the array field automatically and creates the right type of index.

You cannot create a compound index where more than one field is an array. For example, { subjects: 1, grades: 1 } would fail if both subjects and grades are arrays. One array field per compound index is the limit.


Index Options

You can pass options as the second argument to createIndex():

db.collection.createIndex({ field: 1 }, { option: value })

The most useful options:

OptionWhat it doesExample
uniqueNo duplicate values allowed{ unique: true }
nameGive the index a custom name{ name: "students_grade_idx" }
sparseOnly index documents where the field exists{ sparse: true }
expireAfterSecondsAuto-delete documents after N seconds (TTL){ expireAfterSeconds: 3600 }
backgroundBuild index without blocking reads and writes{ background: true }

We cover sparse and expireAfterSeconds in detail in the next file — Index Types.


Listing Indexes

To see all indexes on a collection:

db.students.getIndexes()

Output:

[
  {
    v: 2,
    key: { _id: 1 },
    name: "_id_"
  },
  {
    v: 2,
    key: { name: 1 },
    name: "name_1"
  },
  {
    v: 2,
    key: { grade: 1, enrolled: 1 },
    name: "grade_1_enrolled_1"
  }
]

MongoDB automatically names indexes based on the fields and directions — name_1 for { name: 1 }, grade_1_enrolled_1 for { grade: 1, enrolled: 1 }.


Dropping Indexes

To remove an index you no longer need:

// Drop by index name
db.students.dropIndex("name_1")

// Drop by index specification
db.students.dropIndex({ name: 1 })

To drop all indexes except the _id index:

db.students.dropIndexes()

Dropping an index on a large collection in production can cause a temporary performance spike as queries fall back to collection scans. Always test index changes carefully before applying them to a live database.


School System Indexes

Here are the indexes we should create for our school system based on our most common queries:

// Students — search by name
db.students.createIndex({ name: 1 })

// Students — filter by grade
db.students.createIndex({ grade: 1 })

// Students — filter by grade and enrollment status together
db.students.createIndex({ grade: 1, enrolled: 1 })

// Students — unique email
db.students.createIndex({ email: 1 }, { unique: true })

// Students — search by subjects array
db.students.createIndex({ subjects: 1 })

// Students — sort by enrollment date
db.students.createIndex({ enrollmentDate: -1 })

// Teachers — filter by subject
db.teachers.createIndex({ subject: 1 })

// Teachers — unique email
db.teachers.createIndex({ email: 1 }, { unique: true })

// Courses — filter by grade
db.courses.createIndex({ grade: 1 })

// Courses — unique course code
db.courses.createIndex({ code: 1 }, { unique: true })

createIndex vs ensureIndex

Older MongoDB tutorials use ensureIndex(). This method was deprecated in MongoDB 3.0 and removed in 5.0. Always use createIndex().

// Old — do not use
db.students.ensureIndex({ name: 1 })

// Correct
db.students.createIndex({ name: 1 })

Quick Reference

Index TypeSyntaxUse when
Single field{ name: 1 }Querying or sorting by one field
Unique{ email: 1 }, { unique: true }Field must be unique across all documents
Compound{ grade: 1, enrolled: 1 }Querying or sorting by multiple fields together
Multikey{ subjects: 1 }Field is an array — created automatically

Do not create indexes speculatively — only create them for queries you actually run. Before adding an index, use explain() to confirm the query is doing a collection scan and actually needs one. We cover explain() in detail in the last file of this section.

On this page