Mongoose document outline and validation

I have a circuit like this:

class Schemas constructor: -> @mongoose = require 'mongoose' @schema = @mongoose.Schema @EmployeeSchema = new @schema 'firstname': { type: String, required: true }, 'lastname': { type: String, required: true }, 'email': { type: String, required: true, index: { unique: true }, validate: /\b[a-zA-Z0-9._%+-] +@ [a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}\b/ }, 'departmentId': { type: @schema.ObjectId, required: true } 'enddate': String, 'active': { type: Boolean, default: true } @EmployeeSchemaModel = @mongoose.model 'employees', @EmployeeSchema @DepartmentSchema = new @schema 'name': { type: String, required: true, index: { unique: true } } 'employees' : [ @EmployeeSchema ] @DepartmentSchemaModel = @mongoose.model 'departments', @DepartmentSchema 

So my employees live in an employee document array inside department

I have several department documents that contain several employee documents stored in the employees array.

Then I added a new department , but there were no employees . If I then try to add another department without employees , Mongoose will create a Duplicate key error field for employee.email , which is required. The employee.email field is required and unique, and it should be.

Around this?

+7
source share
3 answers

If you enable Mongoose debug logging with the equivalent of coffeescript mongoose.set('debug', true); , you will see what happens:

 DEBUG: Mongoose: employees.ensureIndex({ email: 1 }) { safe: true, background: true, unique: true } DEBUG: Mongoose: departments.ensureIndex({ name: 1 }) { safe: true, background: true, unique: true } DEBUG: Mongoose: departments.ensureIndex({ 'employees.email': 1 }) { safe: true, background: true, unique: true } 

By embedding the full EmployeeSchema in the DepartmentSchema employees array (and not just the ObjectId link), you create unique indexes for both employees.email and department.employees.email .

Therefore, when you create a new department without any employees, you "use" the undefined mailbox in the department.employees.email index as unique. Therefore, when you try to do this a second time, this unique value is already accepted, and you will get a Duplicate key error .

The best solution for this is probably to change DepartmentSchema.employees into an array of ObjectId references for employees instead of full objects. Then the index remains in the employees collection, where it belongs, and you do not duplicate the data and do not create opportunities for inconsistencies.

+6
source

Check out these links:

http://docs.mongodb.org/manual/core/indexes/#sparse-indexes

mongoDB / mongoose: unique if not null (specifically JohnnyHK answer)

Not to mention that with Mongo 1.8 you can define what is called the sparse index, which only triggers a unique check if the value is not null.

In your case, you need:

 @EmployeeSchema = new @schema 'firstname': { type: String, required: true }, 'lastname': { type: String, required: true }, 'email': { type: String, required: true, index: { unique: true, sparse: true }, validate: /\b[a-zA-Z0-9._%+-] +@ [a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}\b/ }, 'departmentId': { type: @schema.ObjectId, required: true } 'enddate': String, 'active': { type: Boolean, default: true } 

Note that sparse: true added to your index using the EmployeeSchema e-mail attribute.

https://gist.github.com/juanpaco/5124144

+1
source

It looks like you cannot create a unique index in a separate subdocument field. Although the db.collection.ensureIndex function in the Mongo shell allows you to do this, it checks the sub-document as a whole for its uniqueness, and not for a separate field.

You can create an index in a separate subdocument field, you simply cannot make it unique .

0
source

All Articles