Ví dụ middleware Mongoose trong NodeJs

Ví dụ middleware Mongoose trong NodeJs là vấn đề được nhiều lập trình viên quan tâm, bởi những kiến thức trên trường lớp là không đủ, vì vậy bài Ví dụ middleware Mongoose trong NodeJs sẽ chia sẻ tới bạn nhiều thông tin hữu ích

Mọi người vẫn hỏi tôi về việc học lập trình nói chung và NodeJS nói riêng có cần năng khiếu hay quá khó để tiếp cận hay không. Thì tôi có thể trả lời rằng, học lập trình cũng như việc bạn học tiếng Anh hay bất kỳ một ngôn ngữ khác, bởi lập trình...là ngôn ngữ của máy tính, để máy tính đọc và máy tính thực hiện theo yêu cầu của mình, bạn thích là học được.

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.

Hy vọng với bài viết về Ví dụ middleware Mongoose trong NodeJs đã giải đáp giúp bạn phần nào về kiến thức lập trình NodeJS. Như tôi đã nói, ngôn ngữ lập trình không quan trọng bằng tư duy giải thuật, tư duy logic để giải quyết vấn đề.

Với những năm trước đây, lập trình viên là một cái nghề khó và kén chọn người học, đồng nghĩa với việc thu nhập hàng tháng của các lập trình viên luôn cao. Còn những năm gần đây, thì lập trình là môn học phổ thông, và ai cũng nên học một ngôn ngữ lập trình nào đó.

Nếu bạn còn bất kỳ câu hỏi nào trong việc học lập trình online, hãy gửi yêu cầu cho tôi qua email hoidapcode.com@gmail.com hoặc để lại comment bên dưới, tôi sẽ giải đáp trong vòng 24 giờ!

Blog hoidapcode.com là blog được tổng hợp tự động các bài học, thông tin về lập trình trên mạng internet. Nếu bạn có ý kiến hoặc đóng góp về bài viết này, hãy liên hệ với tôi!