Chunk of Code

How to solve MongoDB E11000 duplicate key error when embedded document is null

November 15, 2019

This post is going to be a quick one.

Problem

I encountered a hairy problem today with my mongoose - MongoDB setup. I was fetching new data from an API into my database and I was greeted with the following error message:

E11000 duplicate key error collection: db_name.collection index: field_name.embedded_field_name key: { : null }

My schema is built more less like this:

**GAME SCHEMA**
const gameSchema = mongoose.Schema({
  gameId: {
    type: Number,
    required: true,
    unique: true,
  },
  link: {
    type: String,
    required: true,
    unique: true,
  },
  video: videoSchema,
}

**VIDEO SCHEMA**
const videoSchema = mongoose.Schema({
  videoId: {
    type: Number,
    required: true,
    unique: true,
  },
  link: {
    type: String,
    required: true,
    unique: true,
  },

So the error message was saying that I was trying to insert in the DB a document with a duplicate videoId value of null. This surprised me, because when I designed the schema, I was thinking that the embedded document (video field) was optional.

This is not the case. I had already one game document in the DB without video field so that was already taking up null id for videoId field. I couldn’t add more documents without video field, because their videoId would be null as well.

Solution

I needed a way to still mark the videoId field as unique, but I needed a way to allow multiple null values as well. The solution to this is sparse property.

**VIDEO SCHEMA**
const videoSchema = mongoose.Schema({
  videoId: {
    type: Number,
    required: true,
    unique: true,
	sparse: true,
  },
  ...
}

That small property saved the day. In order for it to work though, the index of the game collection needed to be dropped. The index is created when the first document is inserted in the collection. To recreate it I just dropped the old index reran my fetch script to recreate it.

You can drop MongoDB indexes by running db.collection.dropIndexes().