title: mongoose unique:true pre-save hook calls hook before validation
body: <p>As far as I understand, the mongoose pre-save hooks fire before the document is inserted in the collection but after the validations occur. Therefore if one validation fails, the pre-save hooks won't be called.</p>
  
  <p>In my case, they are called regardless:</p>
  
  <p>What the simple code bellow does is tries to make a schema in which users refer other users by _id when registering. A pre-save hook is added to automatically push the IDs of the new users in their referrals' list.</p>
  
  <p>So user a registers with no referral -> OK</p>
  
  <p>User b registers with a as a referral -> OK</p>
  
  <p>User b2 registers with the same email as b (not OK, is unique) and references a -> SHOULD FAIL and it should not push b2's ID in a.references</p>
  
  <p>Schema:</p>
  
  <pre><code>var userSchema = new Schema({
    email: {type:String, unique:true, required:true},
    isVerified: {type:Boolean, default:false},
    referredBy: {type:Schema.ObjectId, ref:'User'},
    referred: [{type:Schema.ObjectId, ref:'User'}],
  });
  
  userSchema.pre('save', function (next) {
    if (!this.isNew) return next();
    if (!this.referredBy) return next();
  
    User.findById(this.referredBy, function (err, doc) {
      if (err) return next(err);
      if (!doc) return next(new DbError(['referredBy not found: %s', this.referredBy]));
      doc.referred.push(this._id);
      doc.save(next);
    }.bind(this));
  });
  
  userSchema.path('referredBy').validate(function (value, respond) {
    User.findById(value, function (err, user) {
      if (err) throw err;
      if (!user) return respond(false);
      respond(true);
    });
  }, 'doesntExit');
  
  var User = mongoose.model('User', userSchema);
  </code></pre>
  
  <p>Test code:</p>
  
  <pre><code>var a = new User();
  a.email = 'a';
  
  a.save(function () {
      var b = new User();
      b.email = 'b';
      b.referredBy = a._id;
  
      b.save(function () {
          var b2 = new User();
          b2.email = 'b';
          b2.referredBy = a._id;
  
          b2.save(function (err, doc) {
              console.log('error:', err); // duplicate error is thrown, which is OK
              console.log(!!doc);                 // this is false, which is OK
              User.findById(a._id, function (err, result) {
                  console.log('# of referrals: ', result.referred.length); // 2, which is BAD
              });
          });
      });
  });
  </code></pre>
  
  <p>Everything else checks out, the errors are thrown, fails happen, but all the pre-save hooks are saved regardless</p>
  
  <p>Any idea how to fix this or if there is a true pre-save after validation hook?</p>