Tyler Shaddix
Tyler Shaddix

Reputation: 1641

Using "unique" with Nested Objects in Mongoose

So I have a user schema with a nested profile property, and I would like to make sure that all profile id's are unique when the profile property exists:

UserSchema = new Schema {
    ...
    ...
    profile : {
        id : {
           type : String
           unique : true
           sparse : true
        }
        ...
        ...
    }
}

When running my tests, however, I am able to save two different users with the same profile.id value. Is the unique attribute not enforced on nested documents? Am I missing something?

After turning on the logging, I am able to see an output like this (I have removed most fields):

Mongoose: users.ensureIndex({ email: 1 }) { safe: undefined, background: true, unique: true }  
Mongoose: users.insert({ profile: { id: '31056' }) {}  
Mongoose: users.ensureIndex({ 'profile.id': 1 }) { safe: undefined, background: true, sparse: true, unique: true }  
Mongoose: users.insert({ profile: { id: '31056' }) {}

The duplicate value is still being inserted.

Upvotes: 0

Views: 3029

Answers (2)

Tyler Shaddix
Tyler Shaddix

Reputation: 1641

The suggestion by Aaron fixed the race condition caused by indexes being created async. I waited to execute my user schema's unit tests until the index event was emitted:

User.on('index', function (err) { ... })

Upvotes: 0

jviotti
jviotti

Reputation: 18939

Maybe it's validating as unique only inside the nested property. I never trusted unique myself, always went to manual validation, that way I could have more control:

Never worked myself with nestes documents in Mongoose and not very sure if it'll work but at least for you to have an idea:

User.schema.path('profile.id').validate(function(value, respond) {  
  mongoose.models["User"].findOne({ profile.id: value }, function(err, exists) {
    respond(!!exists);
  });
}, 'Profile ID already exists');

Upvotes: 1

Related Questions