【问题标题】:Sequelize validator only returning one error at a timeSequelize 验证器一次只返回一个错误
【发布时间】:2018-09-07 19:44:37
【问题描述】:

使用 Sequelize 在我的数据库中创建或更新项目时,我发现验证器一次只返回一个验证错误。

这并不理想,因为我想在用户提交包含多个错误的表单时将所有错误返回给用户。

这是我的模型:

module.exports = (Sequelize, DataTypes) => {
  const User = Sequelize.define(
    'user',
    {
      email: {
        type: DataTypes.STRING,
        allowNull: false,
        unique: {
          args: true,
          msg: 'That email is not available.'
        },
        validate: {
          isEmail: {
            args: true,
            msg: 'Please enter a valid email.'
          }
        }
      },
      username: {
        type: DataTypes.STRING,
        allowNull: false,
        notEmpty: true,
        unique: {
          args: true,
          msg: 'That username is not available.'
        },
        validate: {
          min: {
            args: USER_USERNAME_MIN_LENGTH,
            msg: 'Please choose a longer username.'
          },
          max: {
            args: USER_USERNAME_MAX_LENGTH,
            msg: 'Please choose a shorter username.'
          },
          is: {
            args: /^[0-9a-zA-Z](\/?[a-zA-Z0-9-_])*\/?$/i,
            msg: 'Please enter a valid username.'
          }
        }
      }
    },
    {
      underscored: true,
    }
  );

  return User;
};

这是我的控制器(在这种情况下,我正在尝试更新用户,例如 User 1 并修改他们的 usernameemail 的值,这恰好是另一个用户的相同值用户,比如User 2)。

try {
  const user = await User.findById(req.user.id);
  if (user) {
    const updatedUser = await user.update({
      username: username || req.user.username,
      email: email || req.user.email
    });

    res.status(200).end();
  }
} catch (err) {
  console.log(err);
  return res.status(500).send(getMappedErrors(err));
}

因此,您可能希望验证器返回 emailusername 字段的错误,因为它违反了 unique 标志。

但是,这就是我在 catch 块中得到的:

{ SequelizeUniqueConstraintError: That username is not available.
    at Query.formatError (/site/node_modules/sequelize/lib/dialects/postgres/query.js:325:18)
    at query.catch.err (/site/node_modules/sequelize/lib/dialects/postgres/query.js:86:18)
    at tryCatcher (/site/node_modules/bluebird/js/release/util.js:16:23)
    at Promise._settlePromiseFromHandler (/site/node_modules/bluebird/js/release/promise.js:512:31)
    at Promise._settlePromise (/site/node_modules/bluebird/js/release/promise.js:569:18)
    at Promise._settlePromise0 (/site/node_modules/bluebird/js/release/promise.js:614:10)
    at Promise._settlePromises (/site/node_modules/bluebird/js/release/promise.js:689:18)
    at Async._drainQueue (/site/node_modules/bluebird/js/release/async.js:133:16)
    at Async._drainQueues (/site/node_modules/bluebird/js/release/async.js:143:10)
    at Immediate.Async.drainQueues [as _onImmediate] (/site/node_modules/bluebird/js/release/async.js:17:14)
    at runCallback (timers.js:763:18)
    at tryOnImmediate (timers.js:734:5)
    at processImmediate (timers.js:716:5)
    at process.topLevelDomainCallback (domain.js:101:23)
  name: 'SequelizeUniqueConstraintError',
  errors:
   [ ValidationErrorItem {
       message: 'That username is not available.',
       type: 'unique violation',
       path: 'username',
       value: 'bob',
       origin: 'DB',
       instance: [user],
       validatorKey: 'not_unique',
       validatorName: null,
       validatorArgs: [] } ],
  fields: { username: 'bob' },
  parent:
   { error: duplicate key value violates unique constraint "users_username_key"
    at Connection.parseE (/site/node_modules/pg/lib/connection.js:545:11)
    at Connection.parseMessage (/site/node_modules/pg/lib/connection.js:370:19)
    at Socket.<anonymous> (/site/node_modules/pg/lib/connection.js:113:22)
    at Socket.emit (events.js:127:13)
    at Socket.emit (domain.js:421:20)
    at addChunk (_stream_readable.js:269:12)
    at readableAddChunk (_stream_readable.js:256:11)
    at Socket.Readable.push (_stream_readable.js:213:10)
    at TCP.onread (net.js:598:20)
     name: 'error',
     length: 204,
     severity: 'ERROR',
     code: '23505',
     detail: 'Key (username)=(bob) already exists.',
     hint: undefined,
     position: undefined,
     internalPosition: undefined,
     internalQuery: undefined,
     where: undefined,
     schema: 'public',
     table: 'users',
     column: undefined,
     dataType: undefined,
     constraint: 'users_username_key',
     file: 'nbtinsert.c',
     line: '434',
     routine: '_bt_check_unique',
     sql: 'UPDATE "users" SET "username"=\'bob\',"email"=\'me@aol.com\',"updated_at"=\'2018-03-28 19:26:27.341 +00:00\' WHERE "id" = 2' } ...

我截断了其余部分,但如您所见,它只返回用户名的错误。当我解决这个问题,然后再次提交我的表单时,我才会收到电子邮件地址的验证错误。

【问题讨论】:

  • 我也遇到了同样的问题,你解决了吗?
  • 我也很好奇这个问题是否得到了解决。 This answer 使用自定义 isUnique 验证函数,该函数为用户名和电子邮件地址调用 find/findOne 方法。这不能在不使用 findOne 方法的情况下完成吗?我想要所有的错误——不仅仅是一个错误。

标签: node.js orm sequelize.js


【解决方案1】:

我有同样的问题。

如果您在属性上设置了allowNull:false 约束,并且该属性的字段为空,则将跳过所有验证器并抛出 ValidationError。因此,首先要检查 db 约束,然后进行常规验证,其中所有错误都按预期在数组中返回。

Here是上面提到的参考

【讨论】:

  • 我有同样的问题,这不是我的问题。我有 2 个字段(用户名和电子邮件),它们都具有非空和唯一约束,并且在尝试创建模型和实例时,我都为这两个字段传递了非空值,并且我只得到了第一个验证错误。正如 OP 所提到的,如果我通过将其更改为未使用的值来修复该错误,则会返回下一个验证错误。
  • 在我的情况下,问题是误解了验证器和约束之间的区别,并期望约束表现得像验证器(即返回多个失败,唯一约束,在这种情况下,在单个抛出错误)。对于任何被这个术语绊倒的人来说,记住区别的一个相当简单的方法是验证器发生在对数据库执行任何 SQL 之前。约束(唯一、非空等)几乎映射到它们的实际数据库表示。
  • 这是触发上述“啊哈!”的文档我的时刻:link
猜你喜欢
  • 2016-07-26
  • 2012-04-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-30
  • 2020-12-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多