Mongoose 是一个用于 Node.js 的 MongoDB 模型库和对象文档映射 (ODM) 库。在 Mongoose 中,开发者可以使用中间件来处理文章操作的过程,包括在创建、更新、删除文章时执行一些前置或后置逻辑。中间件在 Mongoose 中使用非常普遍,但是中间件的执行顺序却经常会带来很多问题,本文将详细介绍 Mongoose 中间件的执行顺序。
Mongoose 中间件的类型
在 Mongoose 中,中间件主要有以下几种类型:
- 钩子函数 (hook): 在执行 CRUD 操作前,会自动执行的函数,可以用于做一些前置处理,如校验、转换数据等。
- 聚合中间件 (aggregate middleware): 应用于 Model.aggregate() 方法的中间件。
- 查询中间件 (query middleware): 应用于 Model.find()、Model.findOne() 等方法的中间件,用于对查询条件和结果进行处理和转换。
- 文档中间件 (document middleware): 应用于文档对象的中间件,包括在保存、修改、验证等操作前自动执行的函数。
- 模型中间件 (model middleware): 应用于模型的中间件,包括在创建模型、更新模型信息等操作前自动执行的函数。
Mongoose 中间件的执行顺序
Mongoose 中间件的执行顺序与它们的类型有关,在执行 CRUD 操作时,默认的钩子函数执行顺序如下:
- 全局钩子函数,这是执行 CRUD 操作前 Mongoose 默认调用的中间件,无论何时都会在执行操作前运行。
- 针对具体 Model 定义的中间件。
- 针对具体 Query 对象实例定义的中间件。
全局钩子函数
全局钩子函数是在每个 Model 上应用的钩子函数,应用所有操作之前调用。因此,全局钩子函数在 Mongoose 中间件执行顺序中是最优先执行的。可以通过以下代码来添加全局钩子函数:
const mongoose = require('mongoose'); mongoose.plugin((schema) => { schema.pre('save', function(next) { // do something next(); }) });
Model 钩子函数
Model 钩子函数是在每个 Model 上应用的钩子函数,在执行任何与操作一起调用之前调用。 在 Model 钩子函数之前,如果有全局钩子函数,则会首先调用全局钩子函数。可以通过以下代码来添加 Model 钩子函数:
// javascriptcn.com 代码示例 const mongoose = require('mongoose'); const blogSchema = new mongoose.Schema({ title: String, content: String }); blogSchema.pre('save', function(next) { // do something next(); });
Query 钩子函数
在默认情况下,Query 中间件将被应用于查询实例和文档实例查询的所有操作。Query 钩子将在文档钩子和模型钩子之后调用。可以通过以下代码来添加 Query 钩子函数:
const mongoose = require('mongoose'); const Blog = mongoose.model('Blog', blogSchema); Blog.find().pre('findOne', function() { // do something });
聚合中间件、文档中间件和模型中间件
聚合中间件、文档中间件和模型中间件在 Mongoose 中间件执行顺序中都是最后执行的。可以通过以下代码来添加聚合中间件、文档中间件和模型中间件:
// javascriptcn.com 代码示例 const mongoose = require('mongoose'); const blogSchema = new mongoose.Schema({ title: String, content: String }); blogSchema.post('save', function(doc) { // do something }); const Blog = mongoose.model('Blog', blogSchema); Blog.add({}, function(err, result) { // do something }); const blog = new Blog({ title: 'Hello, World!', content: 'This is a blog post' }); blog.save(function(err) { // do something });
示例代码
下面是一个示例代码,演示 Mongoose 中间件的执行顺序:
// javascriptcn.com 代码示例 const mongoose = require('mongoose'); mongoose.connect('mongodb://localhost/test'); const blogSchema = new mongoose.Schema({ title: String, content: String }); // 全局钩子函数 mongoose.plugin(schema => { schema.pre('save', function(next) { console.log('4. Global Pre Save'); next(); }); }); // Model 钩子函数 blogSchema.pre('save', function(next) { console.log('3. Model Pre Save'); next(); }); // Query 钩子函数 const Blog = mongoose.model('Blog', blogSchema); Blog.find().pre('findOne', function() { console.log('2. Query Pre FindOne'); }); // 聚合中间件、文档中间件和模型中间件 blogSchema.post('save', function(doc) { console.log('1. Document Post Save'); }); const blog = new Blog({ title: 'Hello, World!', content: 'This is a blog post' }); blog.save(function(err) { console.log('Blog saved!'); });
输出结果:
1. Document Post Save 2. Query Pre FindOne 3. Model Pre Save 4. Global Pre Save Blog saved!
可以看到,聚合中间件、文档中间件和模型中间件最后执行,即使它们的顺序在前面定义。这是因为在执行 CRUD 操作时,实际上是依次调用 Query 钩子、Model 钩子和全局钩子,最后才会执行具体的操作。
总结
Mongoose 中间件的执行顺序是非常重要的,了解了中间件的执行顺序,可以更好地理解 Mongoose 的工作原理,并在实际开发中避免一些问题的发生。在实际使用中,应尽量避免同时使用多种中间件类型,以免影响 Mongoose 中间件的执行顺序。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/654792237d4982a6eb1e9ff5