Mongoose invalidate в хуке предварительной проверки не вызывает ошибку

В моей пользовательской модели есть следующий хук предварительной проверки:

UserSchema.pre<IUser>('validate', async function (next: NextFunction): Promise<void> {
    if (!this.isModified('password')) {
        return next()
    }
    if (this.password.length < 8) {
        this.invalidate(
            'password',
            'Invalid password ...',
            ''
        )
        console.log(this.password)
    }
    this.password = await bcrypt.hash(this.password, 12)
})

Схема такая:

const UserSchema: mongoose.Schema = new mongoose.Schema({
    login: {
        required: true,
        type: String,
        unique: 'Le nom d\'utilisateur `{VALUE}` est déjà utilisé'
    },
    mail: {
        required: true,
        type: String,
        unique: 'Le mail `{VALUE}` est déjà utilisé'
    },
    password: { required: true, type: String, /*select: false*/ },
    // In test env auto validate users
    isVerified: { type: Boolean, default: config.env !== 'test' ? false : true },
    profilPic: { type: mongoose.Schema.Types.ObjectId, ref: 'Image' },
}, { timestamps: true })

Однако при выполнении

try {
   await User.create({ login: 'user2', mail: '[email protected]', password: '123' })
} catch (error) {
   console.log(error)
}

У меня есть журнал 123, который указывает, что код входит во второй if в pre hook, но поскольку журнал находится после this.invalidate, я не понимаю, почему не возникает ошибки.

Я успешно использовал тот же крючок в некоторых других моделях с более сложными операциями без ошибок.

Я действительно не понимаю, почему это не работает


person L. Faros    schedule 25.10.2018    source источник


Ответы (2)


Причиной такого поведения является то, что Document.prototype.invalidate() не вызывает ошибку - он возвращает ошибку. Чтобы остановить выполнение текущей цепочки промежуточного ПО, вам нужно либо вызвать next, либо передать ему эту ошибку:

if (this.password.length < 8) {
    const validationError = this.invalidate(
        'password',
        'Invalid password ...',
        ''
    );
    next(validationError);
    console.log(this.password); // Won't run
}

or throw it:

if (this.password.length < 8) {
    const validationError = this.invalidate(
        'password',
        'Invalid password ...',
        ''
    );
    throw validationError;
    console.log(this.password); // Won't run
}
person Volodymyr    schedule 25.10.2018
comment
Я использовал ту же функцию в другой модели без явных return или throw, но это могло быть на моей стороне - person L. Faros; 25.10.2018
comment
Принцип работы Document.prototype.invalidate() заключается в том, что он добавляет ошибку в карту ошибок экземпляра документа и возвращает ее. Запуск Document.prototype.validate() сразу после аннулирования передаст объект с полем errors и некоторыми метаданными в качестве аргумента обратного вызова validate(). Вы можете проверить это в документации с примером. Возможно, вы не заметили, что invalidate() не выдает, а возвращает ошибку, потому что выполнять больше нечего. - person Volodymyr; 25.10.2018
comment
Попробуйте console.log из значения, возвращенного this.invalidate(), и вы увидите это - person Volodymyr; 25.10.2018
comment
Извините, вчера немного подустал и не заметил, что у меня return next() в другой модели. Оба ваших решения работают, большое спасибо - person L. Faros; 26.10.2018

В документации промежуточного программного обеспечения Mongoose не указана поддерживаемая операция. Вы пробовали с сохранением?

person shmit    schedule 25.10.2018
comment
Возможно, я что-то упустил, но просмотр mongoosejs.com/docs/models.html create - это явно поддерживаемая операция мангуста. - person L. Faros; 25.10.2018
comment
Создание, безусловно, поддерживаемая операция ... просто она не упоминается в списке поддерживаемых операций для промежуточного программного обеспечения. - person shmit; 26.10.2018