CĂN BẢN
SERVER
MYSQL
MONGODB
MODULE
CÁC CHỦ ĐỀ
BÀI MỚI NHẤT
MỚI CẬP NHẬT

Middleware trong Mongoose

Trong bài viết này chúng ta sẽ cùng nhau đi tìm hiểu về Middleware trong Mongoose, trong các bài trước các bạn cũng thấy mình nhắc đến middleware rất nhiều như : validation middleware, save middleware,...bởi vậy bài viết này sẽ tập chung tìm hiểu về các middleware được xây dựng trong Mongoose.

Middleware (pre hay post hooks) là một function mà nó được gọi bất cứ khi nào mà một hàm bất đồng bộ được thực thi. Middleware được chỉ định trong moojy Schema.

1. Một số loại Middleware trong Mongoose

Mongoose có 4 loại middleware: document middleware, model middleware, aggregate middleware, và query middleware.

Trong đó document middleware hỗ trợ việc làm việc với các hàm document. Trong một document middleware chúng ta có các query như:

  • validate
  • save
  • remove
  • updateOne
  • deleteOne
  • init (init hooks là một hàm đồng bộ)

Query middleware hỗ trợ việc theo dõi Model và hàm Query. Trong query middleware chúng ta có một vài query như:

  • count
  • deleteMany
  • deleteOne
  • find
  • findOne
  • findOneAndDelete
  • findOneAndRemove
  • findOneAndUpdate
  • remove
  • update
  • updateOne
  • updateMany

Aggregate middleware hỗ trợ MyModel.aggregate(). Aggregate middleware được thực thi khi bạn gọi hàm exec() trong một aggregate object. Trong Aggregate middleware chúng ta có query như :

  • aggregate

Model middleware hỗ trợ việc theo dõi các model function, Trong Model middleware chúng ta có query như

  • insertMany

Lưu ý : Tất cả các loại middleware đề hỗ trợ pre và post hooks.

2. Pre middleware function

Pre middleware được thực hiện sau mỗi lần được gọi.

var schema = new Schema(..);
schema.pre('save', function(next) {
  // do somethings
  next();
});

Trong mongoose 5.x, thay vì sử dụng next() bạn có thể sử return về một promise. Trong ví dụ bên duới mình sẽ sử dụng async/await :

schema.pre('save', function() {
  return doStuff().
    then(() => doMoreStuff());
});

// Or, in Node.js >= 7.6.0:
schema.pre('save', async function() {
  await doStuff();
  await doMoreStuff();
});

Khi bạn gọi next() nó sẽ được chuyển sang ngay sang middlware tiếp theo mà vẫn chạy câu lệnh ở bên dưới middleware hiện tại. Để chuyển ngay sang middelware tiếp theo mà không thực thi câu lệnh bên dưới thì chúng ta sử dụng return next().

var schema = new Schema(..);
schema.pre('save', function(next) {
  if (foo()) {
    console.log('calling next!');
    // `return next();` sẽ ngăn câu lệnh tiếp theo thực thi
    /*return*/ next();
  }
  // Nếu bỏ return thì câu lệnh này vẫn sẽ chạy.
  console.log('after next');
});

Middleware được sử dụng rất nhiều trong việc xử lý các tác vụ có tính logic cao:

  • Những validation phức tạp.
  • Xóa một doucment phụ thuộc nào đó (ví dụ như xóa một người dùng khỏi blog của bạn đồng thơi sẽ xóa comment, ảnh,vv...)
  • Các hàm bất đồng bộ thông thường.
  • Các tác vụ bất đông bộ chứa nhiều hành động.

Error trong Pre Hooks

Nếu bất cứ pre hook nào xảy ra lỗi, mongoose sẽ không thực thi các subsequent middleware hoặc hooked function. Mà nó sẽ gán vào tham số error trong hàm callback hoặc return reject trong promise. Ở đây chúng ta có một vài cách để bắt error trong pre hooks:

schema.pre('save', function(next) {
  const err = new Error('something went wrong');
  //Gọi next() mà truyền vào một tham số err 
  next(err);
});

schema.pre('save', function() {
  // Return về một project rồi reject lỗi
  return new Promise((resolve, reject) => {
    reject(new Error('something went wrong'));
  });
});

schema.pre('save', function() {
  // Throw error như là một tác vụ đồng bộ
  throw new Error('something went wrong');
});

schema.pre('save', async function() {
  await Promise.resolve();
  // Return error promise (async/await)
  throw new Error('something went wrong');
});



// Hiển thi ra lỗi
myDoc.save(function(err) {
  console.log(err.message); // something went wrong
});

4. Post middleware

Post middleware được thực thi khi sau khi tất các các hook method hay pre middleware được hoàn thành.

schema.post('init', function(doc) {
  console.log('%s đã được bắt đầu', doc._id);
});
schema.post('validate', function(doc) {
  console.log('%s đã được validate (nhưng chưa luư )', doc._id);
});
schema.post('save', function(doc) {
  console.log('%s Đã được lưu', doc._id);
});
schema.post('remove', function(doc) {
  console.log('%s Đã được remove', doc._id);
});

Asynchronous Post Hooks

Nếu bạn gọi 2 posts hook giống nhau, mongoose sẽ thực hiện lần lượt các middleware thứ 1 rồi đến thứ 2.

// Thực hiện middleware này đầu tiên
schema.post('save', function(doc, next) {
  setTimeout(function() {
    console.log('post1');
    //Gọi next()
    next();
  }, 10);
});

// Sau đó đợi middleware trên gọi next() thì middleware này mới chạy
schema.post('save', function(doc, next) {
  console.log('post2');
  next();
});

5. Một vài lưu ý

Dưới đây là một vài lưu ý trong khi làm việc với middleware.

Chỉ định middleware trước Model

Trong trường hợp bạn gọi pre() hay post() sau khi khởi tạo model thường thì sẽ không hoạt động trong Mongoose. Ví dụ bên dưới, pre('save') sẽ không được thực thi.

const schema = new mongoose.Schema({ name: String });

// Compile model từ schema
const User = mongoose.model('User', schema);

//Lúc này mongoose sẽ không gọi pre('save') vì nó được chỉ định sau
//khi complie 
schema.pre('save', () => console.log('Hello from pre save'));

new User({ name: 'test' }).save();

Muốn nó chạy thì bạn phải đặt nó lên trên trước khi complie Model nhé.

const schema = new mongoose.Schema({ name: String });

schema.pre('save', () => console.log('Hello from pre save'));

// Compile model từ schema
const User = mongoose.model('User', schema);


new User({ name: 'test' }).save();

Save/Validate Hooks

Thứ tự thực thi của các pre/post hook sẽ theo thứ thự như sau:

schema.pre('validate', function() {
  console.log('1');
});
schema.post('validate', function() {
  console.log('2');
});
schema.pre('save', function() {
  console.log('3');
});
schema.post('save', function() {
  console.log('4');
});

Naming Conflicts

Mongoose có 2 query và document hooks dành cho remove()

schema.pre('remove', function() { console.log('Removing!'); });

// In ra "Removing!"
doc.remove();

// Không in ra "Removing!". 
// Query middleware cho 'remove' không được thực thi theo các thông thường
Model.remove();

Bạn có thể sử dụng bằng cách thêm tùy chọn vào cho nó.

//  document middleware
schema.pre('remove', { document: true }, function() {
  console.log('Removing doc!');
});

// query middleware.
schema.pre('remove', { query: true }, function() {
  console.log('Removing!');
});

6. Error Handling Middleware

Middleware thông thường bị dừng lại khi middleware đầu tiên gọi next() bị lỗi. Middleware cũng có thể được dùng để bắt các lỗi được xảy ra. Error handling middleware được xác đinh với các tham số nhưng tham số đầu tiên là error chứa các lỗi của middleware.

Ở bên dưới mình có một ví dụ :

var schema = new Schema({
  name: {
    type: String,
    // Will trigger a MongoError with code 11000 when
    // you save a duplicate
    unique: true
  }
});

// Handler **must** take 3 parameters: the error that occurred, the document
// in question, and the `next()` function
schema.post('save', function(error, doc, next) {
  if (error.name === 'MongoError' && error.code === 11000) {
    next(new Error('There was a duplicate key error'));
  } else {
    next();
  }
});

// Will trigger the `post('save')` error handler
Person.create([{ name: 'Axl Rose' }, { name: 'Axl Rose' }]);

Trên đây là những kiến thức cơ bản về Middleware trong Mongoose. Mong bài viết này có thể giúp ích cho bạn cho việc lập trình với NodeJS, cảm ơn bạn đã quan tâm bài viết này.

Cùng chuyên mục:

Crawl dữ liệu website bằng NodeJS cơ bản

Crawl dữ liệu website bằng NodeJS cơ bản

CORS là gì ? Xử lý CORS trong NodeJS

CORS là gì ? Xử lý CORS trong NodeJS

Chắc hẳn trong quá trình xử lý các request tới server thì một vài trường…

Xử lý form trong Express

Xử lý form trong Express

Xây dựng URL trong Express

Xây dựng URL trong Express

Trong bài viết này chúng ta sẽ cùng nhau đi tìm hiểu về cách xây…

Populate trong Mongoose

Populate trong Mongoose

Error Handling & Debugging trong Socket.io

Error Handling & Debugging trong Socket.io

Namespaces & Rooms trong Socket.io

Namespaces & Rooms trong Socket.io

Create / Read / Update / Delete trong Mongoose

Create / Read / Update / Delete trong Mongoose

Validation trong Mongoose

Validation trong Mongoose

Subdocuments trong Mongooose

Subdocuments trong Mongooose

Documents trong Mongoose

Documents trong Mongoose

Trong bài viết này chúng ta sẽ tìm hiểu về documents trong Mongoose

Models trong Mongoose

Models trong Mongoose

SchemaTypes trong Mongoose

SchemaTypes trong Mongoose

Schemas trong Mongoose

Schemas trong Mongoose

Mongoose trong NodeJS

Mongoose trong NodeJS

Làm việc với Table MySQL sử dụng Nodejs

Làm việc với Table MySQL sử dụng Nodejs

Kết nối với MongoDB trong NodeJS

Kết nối với MongoDB trong NodeJS

Giới thiệu MongoDB trong NodeJS

Giới thiệu MongoDB trong NodeJS

Insert / Update / Delete / Select MySQL trong NodeJS

Insert / Update / Delete / Select MySQL trong NodeJS

Broadcasting trong Socket.io

Broadcasting trong Socket.io

Top