【问题标题】:Mongoose unique validation error typeMongoose 唯一验证错误类型
【发布时间】:2012-11-14 20:36:52
【问题描述】:

我将这个架构与来自 npm 的 mongoose 3.0.3 一起使用:

var schema = new Schema({

    _id: Schema.ObjectId,
    email: {type: String, required: true, unique: true}

});

如果我尝试保存已在 db 中的电子邮件,我希望得到一个 ValidationError,就像省略了 required 字段一样。然而事实并非如此,我得到了一个MongoError: E11000 duplicate key error index

这不是验证错误(即使我删除了 unique:true 也会发生)。

知道为什么吗?

【问题讨论】:

  • 旁注:latest npm mongoose 在周/月/年可能毫无意义。放上你正在使用的版本。
  • 即使在您删除 unique: true 之后它也会继续这样做,因为就像 alexjamesbrown 所说,该规范会在您的数据库上创建一个索引。该数据库和索引会一直存在,直到您删除索引或数据库。您可能已经明白这一点,但我认为说出来可能会对某人有所帮助。

标签: node.js mongodb mongoose


【解决方案1】:

我更喜欢把它放在路径验证机制中,比如

UserSchema.path('email').validate(function(value, done) {
    this.model('User').count({ email: value }, function(err, count) {
        if (err) {
            return done(err);
        } 
        // If `count` is greater than zero, "invalidate"
        done(!count);
    });
}, 'Email already exists');

然后它将被包装到 ValidationError 中,并在您调用 validatesave 时作为第一个参数返回。

【讨论】:

  • 这是正确答案。它应该是路径的自定义验证器,而不是预保存功能。
  • 这可行,但在某些情况下,当 this 不是指模型的文档/实例,而是实际模型本身时,使用 this.model 可能会引发错误。处理所有场景并避免引发错误的安全方法是改用 mongoose.model('User', UserSchema)。
  • @user3344977 为什么这比预存功能好?
  • @JasonAllan 老实说,我不记得了,而且很长时间没有使用猫鼬了。抱歉,我真的应该在评论中提供更多细节。
  • 以上代码给出 DeprecationWarningcollection.count 已弃用,将在未来版本中删除
【解决方案2】:

我对批准的答案有一些问题。即:

  1. this.model('User') 对我不起作用。
  2. 回调done 工作不正常。

我通过以下方式解决了这些问题:

  UserSchema.path('email').validate(async (value) => {
    const emailCount = await mongoose.models.User.countDocuments({email: value });
    return !emailCount;
  }, 'Email already exists');

我使用async/await,这是个人偏好,因为它更整洁:https://javascript.info/async-await

如果我有什么问题,请告诉我。

【讨论】:

    【解决方案3】:

    这是预期行为

    unique: true 相当于在 mongodb 中这样设置索引:

    db.myCollection.ensureIndex( { "email": 1 }, { unique: true } )
    

    要使用 Mongoose 进行这种类型的验证(Mongoose 称之为复杂的验证,例如,您不只是断言该值是一个数字),您需要连接到 pre-save 事件:

    mySchema.pre("save",function(next, done) {
        var self = this;
        mongoose.models["User"].findOne({email : self.email},function(err, results) {
            if(err) {
                done(err);
            } else if(results) { //there was a result found, so the email address exists
                self.invalidate("email","email must be unique");
                done(new Error("email must be unique"));
            } else {
                done();
            }
        });
        next();
    });
    

    【讨论】:

    【解决方案4】:

    简单响应json

    try {
      let end_study_year = new EndStudyYear(req.body);
      await end_study_year.save();
       res.json({
        status: true,
        message: 'បានរក្សាទុក!'
       })
      }catch (e) {
       res.json({
       status: false,
       message: e.message.toString().includes('duplicate') ? 'ទិន្នន័យមានរួចហើយ' : e.message.split(':')[0] // check if duplicate message exist
      })
     }
    

    【讨论】:

      【解决方案5】:

      很抱歉回答了一个老问题。经过测试,我感觉很好,找到了这些答案,所以我将给出我的经验。两个最佳答案都很好且正确,请记住:

      • 如果你的文档是新的,你可以验证count是否大于0,这是常见的情况;
      • 如果您的文档不是新文档并且修改了unique 字段,您也需要使用 0 进行验证;
      • 如果您的文档不是新文档并且没有被修改,请继续;

      这是我在代码中所做的:

      UserSchema.path('email').validate(async function validateDuplicatedEmail(value) {
          if (!this.isNew && !this.isModified('email')) return true;
      
          try {
              const User = mongoose.model("User");
      
              const count = await User.countDocuments({ email: value });
              if (count > 0) return false;
      
              return true;
          }
          catch (error) {
              return false;
          }
      }, "Email already exists");
      
      
      

      【讨论】:

        猜你喜欢
        • 2015-03-30
        • 2015-06-23
        • 2014-08-27
        • 2016-10-22
        • 2016-09-11
        • 2020-03-12
        • 2020-07-01
        • 1970-01-01
        • 2018-02-19
        相关资源
        最近更新 更多