【问题标题】:How to catch the error when inserting a MongoDB document which violates an unique index?插入违反唯一索引的 MongoDB 文档时如何捕获错误?
【发布时间】:2015-08-16 02:46:46
【问题描述】:

我正在构建一个 MEAN 应用程序。

这是我的用户名架构,用户名应该是唯一的。

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

module.exports = mongoose.model('User', new Schema({ 
    username: { type: String, unique: true }
}));

在我的发布路线上,我这样保存用户:

app.post('/authenticate', function(req, res) {
        var user = new User({
            username: req.body.username
        });

        user.save(function(err) {
            if (err) throw err;

            res.json({
                success: true
            });

        });
    })

如果我再次使用相同的用户名发帖,我会收到此错误:

MongoError: insertDocument :: 由 :: 11000 E11000 重复键引起 错误索引:

有人能解释一下如何代替错误发送像{ succes: false, message: 'User already exist!' }这样的json

注意:我发布用户后,我会自动验证,不需要密码或其他任何东西。

【问题讨论】:

    标签: javascript mongodb express mongoose mean


    【解决方案1】:

    您将需要测试从 save 方法返回的错误,以查看它是否因重复用户名而引发。

    app.post('/authenticate', function(req, res) {
      var user = new User({
        username: req.body.username
      });
    
      user.save(function(err) {
        if (err) {
          if (err.name === 'MongoError' && err.code === 11000) {
            // Duplicate username
            return res.status(422).send({ succes: false, message: 'User already exist!' });
          }
    
          // Some other error
          return res.status(422).send(err);
        }
    
        res.json({
          success: true
        });
    
      });
    })
    

    【讨论】:

    • 500 不应用作状态码,因为它不是内部服务器错误。所以你可以使用 400 来处理数据冲突。
    • 如果您有多个唯一字段,则此处理方法无效,因为它总是返回相同的错误代码。
    • 如果我在一个文档中有两个唯一字段怎么办?如何给出明确的消息是哪个字段导致错误。例如:我们可以让用户的电子邮件和别名字段都应该是唯一的?
    【解决方案2】:

    你也可以试试这个不错的包mongoose-unique-validator,它使错误处理变得更加容易,因为当你尝试违反唯一约束时,你会得到一个 Mongoose 验证错误,而不是 E11000 错误来自 MongoDB:

    var mongoose = require('mongoose');
    var uniqueValidator = require('mongoose-unique-validator');
    
    // Define your schema as normal.
    var userSchema = mongoose.Schema({
        username: { type: String, required: true, unique: true }
    });
    
    // You can pass through a custom error message as part of the optional options argument:
    userSchema.plugin(uniqueValidator, { message: '{PATH} already exists!' });
    

    【讨论】:

      【解决方案3】:

      试试这个:

      app.post('/authenticate', function(req, res) {
              var user = new User({
                  username: req.body.username
              });
      
              user.save(function(err) {
                  if (err) {
                      // you could avoid http status if you want. I put error 500 
                      return res.status(500).send({
                          success: false,
                          message: 'User already exist!'
                      });
                  }
      
                  res.json({
                      success: true
                  });
      
              });
          })
      

      【讨论】:

      • 谢谢,工作正常,我正在考虑这个问题,但我认为错误可以返回现有用户错误以外的其他内容,我错了吗?
      • 是的,但这是常见的情况:“尝试保存用户”,如果出现错误,您认为该用户是重复的。您可以向用户显示一条简单的消息,例如“用户已存在”,然后将真正的错误存储在您的日志中,以查看数据库是否存在错误。
      • 不推荐,应该做具体的错误处理。至少应该处理错误代码和错误消息。
      • 同意 Diego Gallegos,对于生产用例,始终建议处理逻辑与操作错误,“找不到记录”与“数据库无法连接/超时/任何”不同跨度>
      • 最好使用 try-catch 并读取错误数
      【解决方案4】:

      以下是使用类型错误而不是字符串来验证它的方法:

      // your own error in a diff file
      class UniqueError extends Error {
        constructor(message) {
          super(message)
        }
      }
      
      // in your service file
      const { MongoError } = require('mongodb')
      
      class UserService {
        async createUser(userJSON) {
          try {
            return await User.create(userJSON)
          } catch (e) {
            if (e instanceof MongoError && e.code === 11000) {
              throw new Error('Username already exist')
            }
            throw e
          }
        }
      }
      
      // in your controller file
      class UserController {
        async create(req, res) {
          const userJSON = req.body
          try {
            return res.status(201).json(await userService.createUser(userJSON))
          } catch (e) {
            if (e instanceof UniqueError) {
              return res.status(422).json({ message: e.message })
            }
            return res.status(500).json({ message: e.message })
          }
        }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-03-16
        • 2014-02-23
        • 2017-08-16
        • 1970-01-01
        • 2013-11-27
        • 2016-03-15
        • 2016-07-27
        相关资源
        最近更新 更多