alkhatim
alkhatim

Reputation: 363

mongodb (mongoose) throws E11000 duplicate key error collection

I have a state model which is a lookup with just a name that i have set to unique because i don't want two states with the same name. now I have vacation model with a state property that i have set to the state schema. error E11000 duplicate key error collection is thrown after the first vacation is inserted when I insert a second vacation with the same state.I know mongodb throws the exception because I already have a vacation with the state.name as the first one.

const stateSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true,
    minlength: 1,
    maxlength: 30,
    unique: true
  }
});

const State = mongoose.model("State", stateSchema);

------------------------------------------------------

const vacationSchema = new mongoose.Schema({

-- some properties

  state: {
    type: stateSchema,
    required: true
  }

-- some properties

});

const Vacation = mongoose.model("Vacation", vacationSchema);

so how can i force unique state names in the states collection, but allow multiple vacations to have the same state in the vacations state? do I have to explicitly change state: {type: stateSchema} to {type: new Schema(...etc ?

Upvotes: 0

Views: 757

Answers (1)

whoami - fakeFaceTrueSoul
whoami - fakeFaceTrueSoul

Reputation: 17915

You've two options :

  1. If there is only one field name in State collection, also if it doesn't change(kind of nothing like rename/alter), Plus every vacation document contains only one state name then you would include state name value in state field directly in your Vacation document, this helps in if you don't want to hit other collection every time you query Vacation plus no need to maintain two collections. There is no point of directly storing names in Vacation collection if you're maintaining State collection, as there won't be any validation whether a given name exists in State collection or not, unless you do a DB call to check it before inserts to Vacation, because storing data into collections is independent - So you might need to remove unique : true from stateSchema, your code should work, as the above code is about storing data into Vacation or simply in Vacation schema make State as string & use State schema for storing data into State Collection.

  2. Or if you really need to maintain another collection as what you've now, then you need to have a mapping between documents in State collection to documents in Vacation. This is helpful if most documents in Vacation will have multiple State names in array field. Where State names are unique in State collection. Optimal way of having relation is thru _id of State documents. If need to do that then make changes in Vacation Schema as,

    state: {
      type: [{ type: Schema.Types.ObjectId, ref: 'State' }],// you can make this single value instead of array.
      required: true
    }
    

    After this you need to use .populate() on reads - Ref : mongoose populate

    If you want to store state name as value in Vacation collection, then make state field as string, then you can use .populate() on reads - Ref : mongoose populate virtuals or similar to mongoDB's native $lookup - Ref : mongoDB $lookup

Note :

  1. Uniqueness on State name helps when you've transactions related to State and also you need separate collection when you need to make frequent changes only on State related data + on reads as well you need only data related to State or Vacation - you make those independent as State is unique you can refer that in vacation.
  2. Not only in mongoose schema, you also create unique index on a field, that way it will be on DB level which helps either way when running queries directly on DB or thru code, whereas mongoose schema triggers thru code, Also when you create an unique index on existing collection & runs into issue means there is already duplicate data for that field.

Upvotes: 1

Related Questions