0

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.

Tyler Shaddix
  • 1,621
  • 2
  • 15
  • 20
  • 1
    Yes, unique indexes are enforced on nested docs. What's probably happening is that it can't create the index because you've already got duplicates. See [this answer](http://stackoverflow.com/a/12453041/1259510) for some tips on debugging this. – JohnnyHK Apr 02 '13 at 21:56
  • Thanks for the suggestion Johnny, but I have been dropping the database in between the tests, so I don't think this is the case. I will be using the steps in the link you provided to do some debugging. – Tyler Shaddix Apr 02 '13 at 23:09
  • 1
    Index creation is async as well. It may be a race condition. Try waiting for the index event before insertion. – aaronheckmann Apr 05 '13 at 00:33
  • User.on('index', function (err) { ... }) – aaronheckmann Apr 05 '13 at 00:34
  • Thanks Aaron, that has fixed the issue. The logs seemed to be indicating a delayed index creation, which would indicate a race condition like you suggested. Wonderful tool, thanks again for the help! – Tyler Shaddix Apr 05 '13 at 03:20

2 Answers2

1

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');
jviotti
  • 17,881
  • 26
  • 89
  • 148
0

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) { ... })
Community
  • 1
  • 1
Tyler Shaddix
  • 1,621
  • 2
  • 15
  • 20