Mongoose 中的中间件详解及使用示例

前言

Mongoose 是 Node.js 环境下非常流行的 MongoDB ODM(Object Document Mapping)库,它提供了一种方便的抽象层,让我们可以更加轻松地以面向对象的方式操作 MongoDB 数据库,同时还给我们带来了很多方便的特性,例如自动创建集合、数据校验、中间件等等。

其中,中间件是 Mongoose 的一个非常重要的特性之一,它可以让我们在执行一些特定的操作前或者后,自动地执行一些逻辑,例如日志输出、权限校验、数据修改等等。在本文中,我们将会详细地介绍 Mongoose 中间件的使用和实现方式,并提供一些示例来帮助读者更好地理解和应用这个特性。

中间件的类型

Mongoose 中的中间件一共有四种类型,分别是 Document MiddlewareModel MiddlewareAggregate MiddlewareQuery Middleware,下面我们将逐一进行介绍。

Document Middleware

Document Middleware 是对单个文档执行的中间件,它主要包括两种类型:prepostpre 中间件会在执行 savevalidate 方法之前自动执行,而 post 中间件会在执行了 savevalidate 方法后自动执行,具体的实现方式非常简单,我们只需要在模型定义中添加对应的钩子函数即可。

const userSchema = new mongoose.Schema({
  name: String,
  age: Number
});

userSchema.pre('save', function(next) {
  // do something before save
  next();
});

userSchema.post('save', function(doc) {
  // do something after save
});

const User = mongoose.model('User', userSchema);

在上面的代码中,我们定义了一个 User 模型,并增加了一个 pre 和一个 post 中间件,其中 pre 中间件在执行 Usersavevalidate 方法之前自动执行,而 post 中间件则是在执行 savevalidate 方法后执行。

Model Middleware

Model Middleware 是对整个模型执行的中间件,它也包括 prepost 两种类型。pre 中间件在执行 initremoveupdateOnefindOneAndDelete 等方法之前自动执行,而 post 中间件则是在执行了这些方法之后自动执行,同样的,我们只需要在模型定义中添加对应的钩子函数即可。

userSchema.pre('init', function(next) {
  // do something before init
  next();
});

userSchema.post('remove', function(doc) {
  // do something after remove
});

const User = mongoose.model('User', userSchema);

在上面的代码中,我们定义了一个 User 模型,并增加了一个 pre 和一个 post 中间件,其中 pre 中间件在执行 initremoveupdateOnefindOneAndDelete 等方法之前自动执行,而 post 中间件则是在执行了这些方法之后执行。

Aggregate Middleware

Aggregate Middleware 是对聚合操作执行的中间件,它也包括 prepost 两种类型,同样地,我们也只需要在模型定义中添加对应的钩子即可。

userSchema.pre('aggregate', function(next) {
  // do something before aggregate
  next();
});

userSchema.post('aggregate', function(results) {
  // do something after aggregate
});

const User = mongoose.model('User', userSchema);

在上面的代码中,我们定义了一个 User 模型,并增加了一个 pre 和一个 post 中间件,其中 pre 中间件在执行聚合操作之前自动执行,而 post 中间件则是在执行了聚合操作后执行。

Query Middleware

Query Middleware 是对查询操作执行的中间件,它也包括 prepost 两种类型,同样地,我们也只需要在模型定义中添加对应的钩子即可。

userSchema.pre('count', function(next) {
  // do something before count
  next();
});

userSchema.post('find', function(results) {
  // do something after find
});

const User = mongoose.model('User', userSchema);

在上面的代码中,我们定义了一个 User 模型,并增加了一个 pre 和一个 post 中间件,其中 pre 中间件在执行查询操作之前自动执行,而 post 中间件则是在执行了查询操作后执行。

中间件的使用

Mongoose 中间件的使用非常简单,我们只需要在模型定义中添加对应的钩子函数,然后再执行对应的操作即可,下面我们将以一个使用 Document Middleware 的示例来说明中间件的使用方法。

const userSchema = new mongoose.Schema({
  name: String,
  email: String,
  password: String
});

// pre-save logic
userSchema.pre('save', function(next) {
  const user = this;

  // only hash the password if it has been modified (or is new)
  if (!user.isModified('password')) return next();

  // hash the password
  bcrypt.hash(user.password, 10, function(err, hash) {
    if (err) return next(err);

    // override the cleartext password with the hashed one
    user.password = hash;
    next();
  });
});

const User = mongoose.model('User', userSchema);

const newUser = new User({ name: 'John', email: 'john@example.com', password: '123456' });

newUser.save((err, user) => {
  if (err) return console.error(err);

  console.log(user);
});

在上面的代码中,我们定义了一个 User 模型,并增加了一个 pre 中间件,在执行 save 方法之前自动执行,我们在这个中间件中判断密码是否被修改过,如果是,我们就使用 bcrypt 库对密码进行哈希加密,然后再将加密后的密码存储到数据库中。

最后,在我们执行 save 方法时,中间件会自动被调用,执行我们添加的逻辑。

总结

本文详细介绍了 Mongoose 中的中间件,包括中间件类型和使用方法等方面,希望能对读者有所帮助。在使用中间件时,需要根据实际需求选择对应的类型,并编写对应的钩子函数,以便实现自定义的逻辑。同时,在编写过程中需要注意,因为中间件是一个全局的特性,所以需要尽可能地减少不必要的中间件,以免影响应用性能。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/6591277ceb4cecbf2d6614ab


纠错反馈