Validation trong Mongoose

Phùng Hùng

Phùng Hùng

Teacher and Programmer

Trước khi bắt đầu, bạn cần biết một số quy tắc sau đây đối với validation trong mongoose:

  • Validation phải được định nghĩa trong đối tượng SchemaType.
  • Validation bản chất là một pre('save') middleware do mongoose tự tạo ra.
  • Bạn có thể vô hiệu hóa validation trước khi lưu document bằng tùy chọn validateBeforeSave: schema.set('validateBeforeSave', true).
  • Bạn có thể chạy validation thủ công bằng phương thức validate hoặc validateSync.
  • Có thể đánh dấu một trường là không hợp lệ bằng phương thức invalidate.
  • Các validator không thể chạy với giá trị undefined. Ngoại lệ duy nhất là required validator.
  • Validation hoạt động bất đồng bộ theo cơ chế đệ quy; khi gọi save, validation ở subdocument đươc thực hiện trước.
  • Có thể tùy chỉnh được quá trình validation.

Các validator có sẵn

  • Tất cả các SchemaType đều có thể sử dụng required validator.
  • Các số có các validator riêng là minmax.
  • Các chuỗi có các validator riêng là enum, match, minglengthmaxlength.
const breakfastSchema = new Schema({
eggs: {
type: Number,
min: [6, 'Too few eggs'],
max: 12,
},
bacon: {
type: Number,
required: [true, 'Why no bacon?'],
},
drink: {
type: String,
enum: ['Coffee', 'Tea'],
required: function () {
return this.bacon > 3;
},
},
});

Tùy chọn unique không phải là validator

Tùy chọn unique thực ra không phải là validator mà là môtj unique index.

Custom Validator

Custom validator là một hàm đươc truyền vào cho thuộc tính validate của SchemaType.

Validator đông bộ

const userSchema = new mongoose.Schema({
phone: {
type: String,
validate: {
validator: function (value) {
return /\d{3}-\d{3}-\d{4}/.test(value);
},
message: props => `${props.value} is not a valid phone number!`,
},
required: [true, 'User phone number required'],
},
});

Validator bất đồng bộ

Nếu validator trả về một promise (như hàm async) mongoose sẽ đợi đến khi promise này settle. Nếu promise bị reject hoặc resolve với giá trị false, Mongoose xem như có lỗi xác thực.

const userSchema = new mongoose.Schema({
name: {
type: String,
// If the promise rejects, Mongoose assumes
// the validator failed with the given error.
validate: () => Promise.reject(new Error('Oops!')),
},
email: {
type: String,
validate: {
// If the promise resolves to `false`
// Mongoose assumes the validator failed
// and creates an error with the given `message`.
validator: () => Promise.resolve(flase),
message: 'Email validation failed',
},
},
});

Lỗi xác thực

Lỗi trả về bởi Mongoose sau khi có lỗi xác thực là một đối tượng có chứa errors là một đối tượng của class ValidatorError. Mỗi đối tượng của ValidatorError đều có các thuộc tính sau:

  • kind: kiểu lỗi
  • path: path có giá trị không hợp lệ.
  • value: giá trị không hợp lệ
  • message: thông báo lỗi.

Trong các thuộc tính này, thuộc tính message có thể tùy chỉnh trong đối tượng truyền vào validate.

Lỗi ép kiểu

Trước khi xác thực giá trị, Mongoose chuyển nó thành kiểu đươc khai báo trong SchemaType. Quá trình này gọi là casting document. Nếu quá trình casting bị lỗi ở path nào đó đôi tượng errors ở trên sẽ là đôi tượng của lớp CastError.

Vì validation chạy sau casting, nên nếu casting có lỗi, đối số value của validator có thể là null, undefined hoặc một đối tượng nào đó.

Các update validator

Trên ta nói về các document validator. Tức các validator được chạy trước khi document được .save().

Mongoose cũng hỗ trợ các validator này cho các phương thức cập nhật document sau:

  • update()
  • updateOne()
  • updateMany()
  • findOneAndUpdate()

Mặc định các validator được tắt, để bật lại cần cài đặt tùy chọn runValidators thành true.

Update Validator và this

Có một sự khác biệt cơ bản giữa update validator và document validator đó là từ khóa this.

  • Khi sử dụng document validator: this trỏ đến document sẽ được xác thực.
  • Khi sử dụng update validator: thisundefined.

Để sử dụng this trong validator, nó cần phải là hàm thông thường, không được phép là hàm mũi tên.

Update Validator chỉ chạy với các hành động sau

  • $set
  • $unset
  • $push
  • $addToSet
  • $pull
  • $pullAll