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.

5
  • 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 for some tips on debugging this. Commented Apr 2, 2013 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. Commented Apr 2, 2013 at 23:09
  • 1
    Index creation is async as well. It may be a race condition. Try waiting for the index event before insertion. Commented Apr 5, 2013 at 0:33
  • User.on('index', function (err) { ... }) Commented Apr 5, 2013 at 0: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! Commented Apr 5, 2013 at 3:20

2 Answers 2

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');
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for your solution, I will be using it if unique on nested documents does not behave as I expected.
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) { ... })

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.