Search code examples
mongoosemongoose-schema

Mongoose Schema: enforcing mutually exclusive keys


The data my API will receive contains one of two keys, option1 or option2, but not both.

I want to enforce that behaviour in my mongoose schema but have found nothing that would do this, is there a way to link two keys and make sure one (and only one) of them exists?

Example code:

const exampleSchema = new mongoose.Schema({
  custRef: {
    type: String,
    required: true,
    trim: true
  },
  option1: {
    type: Number
  },
  option2: {
    type: Number
  }
});

Example JSON 1:

{
    "custRef": "abc123",
    "option1": 456
}

Example JSON 2:

{
    "custRef": "abc789",
    "option2": 010
}

Solution

  • You can use a pre validate hook like this:

    (note that I removed custRef field for simplicity)

    const mongoose = require("mongoose");
    
    const exampleSchema = new mongoose.Schema({
      option1: {
        type: Number
      },
      option2: {
        type: Number
      }
    });
    
    exampleSchema.pre("validate", function(next) {
      //console.log(this);
      if (this.option1 && this.option2) {
        let err = new Error("Both options not allowed");
        err.status = 400;
        next(err);
      } else if (!(this.option1 || this.option2)) {
        let err = new Error("One of the options is required");
        err.status = 400;
        next(err);
      }
    
      next();
    });
    
    const Example = mongoose.model("Example", exampleSchema);
    
    const example = new Example({});
    
    example.validate().catch(err => {
      console.log(err.message);
    });
    
    
    

    This may not work for update operations, so be careful.

    Docs:

    https://mongoosejs.com/docs/middleware.html#order