之前的文章以一个demo介绍了Mongoose的入门知识,本文深入Mongoose介绍它的核心概念------中间件。
中间件又称为 pre-hook 和 post-hook,它是在特定动作之前或特定动作之后要执行的函数,比如说,你想在 document 保存到数据库之前执行某些函数,那么应该用 pre-hook 来实现。如果想事后执行什么,那么应该用 post-hook 来实现。pre-hook、post-hook 和特定动作的执行顺序可以总结为:pre-hooks -> method -> post-hooks。
pre-hook 和 post-hook 都需要添加在 Schema 上,并且要在调用 mongoose.model() 之前添加,示例代码如下:
javascript
teacherSchema.pre('save', function() {
console.log('save pre one')
})
teacherSchema.pre('save', function() {
console.log('save pre two')
})
teacherSchema.post('save', function() {
console.log('save post one')
})
Mongoose 有 document、model、aggregate 和 query 这 4 种类型的中间件,每类中间件支持的函数有所不同,中间件中 this 的指向也不同,比如 document 中间件支持 save 和 remove 等函数,其 this 指向 document;query 中间件支持 remove 和 find 等函数,其 this 指向 query;model 中间件只支持 insertMany 函数,其 this 指向 model;aggregate 中间件只支持 aggregate 函数,其 this 指向 aggregate 对象。访问 mongoosejs.com/docs/middle... 查看中间件的更多细节。
pre-hook
顾名思义,在特定动作之前要执行的函数要用 pre-hook 来实现,如果在 pre-hook 中发生了错误那么随后要执行的特定动作将不会被执行。在 pre-hook 中可以用 throw 抛出错误,也能返回一个 rejected 的 promise 对象,这两种都会认为 pre-hook 发生了错误。
以下是一些使用 pre-hook 的用例:
- 在查询的时候添加额外的查询条件或修改查询条件。
- 删除与 document 相关的 document,比如删除用户之前,先删除与他相关的评论等。
- 在保存 document 之前格式化用户提交的数据,比如将 firstName 和 lastName 拼接成fullName 再保存到数据库。
post-hook
post-hook在特定动作执行之后执行,访问 mongoosejs.com/docs/middle... 查看它与 pre-hook 在语法上的细微差异。
命名冲突
如前所述,中间件都添加在Schema上,有些函数即被document中间件支持也被query中间件支持,remove就是这样一个例子,此时就出现了命名冲突。需要记住的是,这些有命名冲突的中间件默认是document中间件,如果要将它们用作query中间件,那么添加中间件时需要传递一个配置项。代码如下:
javascript
// document 中间件
teacherSchema.pre('remove', { document: true, query: false }, function() {
console.log('移除 document');
})
// query 中间件
teacherSchema.pre('remove', { document: false, query: true }, function() {
console.log('即将执行Model.remove(),从 collection 中移除所有符合条件的 document');
})