Even though I’ve been using MongoDB for the last few years, I’m still very much a noob when it comes to a lot of things.

One of those things would be unique indexes.

Generally speak, I interact with MongoDB three different ways:

  1. I write code that explicitly creates something with no duplicate concerns
  2. I perform an update on a record using it’s primary key / ID
  3. I will do a findOneAndUpdate with the upsert flag set to true.

Channelling a bit of my Pythonic roots, I don’t really like asking for permissions. In an age of Promises, I’m writing more and more try / catch blocks that just try to do stuff and will handle the fall out if an error is encountered.

Back when the world was dominated by RDBMSes and I was using MySQL for just about everything, I would approach tables with unique indexes in the same Pythonic way, just try it and see.

This would result in code that would try to write to a table (sans a lookup to see if a record already exists) and if there was an error, I would check the error code to figure out if the record already existed or if something else happened.

That would result in code that didn’t do an unnecessary lookup at the beginning and would still be able to handle collisions against the unique key.

I wanted to do the same thing with MongoDB, but back to my noob status, I had never actually created any indexes on a collection (don’t judge ;)

Fortunately, Mongoose (our ODM of choice) makes things very simple and you can define an index on individual fields as well as a compound index that spans multiple fields.

I needed both and thought it was worth putting a post together about it as I had to root around for a bit to find what I was looking for.

Single Field Unique Indexes

To add a unique index to a single column, we simply add a unique property to the field.

Let’s say we have a collection of fruits to track which ones are edible and we want to make the name of the fruit to be unique. We’d simply add the additional property and Mongoose will take care of the rest!

const mongoose = require('mongoose');

const fruitSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true,
    unique: true,
  },
  isEdible: {
    type: Boolean,
    default: false,
  },
});

module.exports = mongoose.model('Fruit', fruitSchema);

Multiple Field (Compound) Unique Indexes

Adding an index to a single field is pretty trivial, but if you want to add an index to more than one field, simply adding the unique property isn’t going to cut it.

For this example, let’s say we have a collection that represents different mango varieties and their country of origin and whether or not the fruit is the country of origin’s national fruit.

In this scenario, we could make the variety and country of origin unique.

const mongoose = require('mongoose');

const mangoSchema = new mongoose.Schema({
  variety: {
    type: String,
    required: true,
  },
  countryOfOrigin: {
    type: String,
    required: true,
  },
});

mangoSchema.index({
  variety: 1,
  countryOfOrigin: 1,
}, {
  unique: true,
});

module.exports = mongoose.model('Mango', mangoSchema);

Internally, Mongoose will take care of creating the defined indexes when the process is restarted and you’ll be good to go!

Comment below if you think I should have went with indices instead of indexes for this particular post ;)