Search code examples
mongodbvalidationmongooseunique

The unique Option is Not a Validator in Mongoose


I am reading the document of validation in Mongoose. But I don't get this part, can someone explain to me with different examples?

It says "A common gotcha for beginners is that the unique option for schemas is not a validator." What does it mean? Thanks!


Solution

  • The unique option is used to create a unique index on the specified field in an underlying MongoDB collection. Mongoose validator options such as max and required perform validations on the application level before queries are sent to MongoDB. Take for example a transactions schema defined as follows:

    const TransactionSchema = mongoose.Schema({
      transactionType: { type: String, required: true },
      amount: { type: Number, required: true, min: 1 },
    }, { timestamps: true });
    

    Say we want to insert a new transaction to the underlying transaction collection as shown:

    await Transaction.create([{
       transactionType: 'credit',
       amount: 0, // amount < min thus mongoose throws a validation exception.
    }]);
    

    In the snippet above, mongoose will raise a validation exception for the amount property within your application and the request will not hit the database. The unique option however does not behave this way. It does not validate properties on the application level. Its sole job is to build a unique index in your database.

    In a situation where the index has not been built, two or more documents can end up sharing a value that was intended to be unique. This scenario is the 'race condition' referred to below.

    const uniqueUsernameSchema = new Schema({
      username: {
        type: String,
        unique: true
      }
    });
    const U1 = db.model('U1', uniqueUsernameSchema);
    const U2 = db.model('U2', uniqueUsernameSchema);
    
    const dup = [{ username: 'Val' }, { username: 'Val' }];
    U1.create(dup, err => {
      // Race condition! This may save successfully, depending on whether
      // MongoDB built the index before writing the 2 docs.
    });
    

    However, if the unique index has been built and the operation above is run, MongoDB (not mongoose) will raise an error. Hence why you should wait for mongoose to finish building the unique index before writing.