【问题标题】:Get model count in Mongoose pre hooks在 Mongoose 预挂钩中获取模型数量
【发布时间】:2017-04-18 12:46:53
【问题描述】:

如何在saveupdate Mongoose pre hooks/middlewares 中获取特定模型的文档计数?

考虑到thisupdate 钩子中的查询,这很好用:

schema.pre('update', function (next) {
  this.model.count().then...
});

但是在save 钩住这个

schema.pre('save', function (next) {
  this.count().then...
});

结果

this.count 不是函数

在调试回调时,save 钩子中的 thisupdate 钩子中的 this.model 似乎是“模型”(Model 的实例)。他们之间有什么区别?

为什么save钩子中的模型实例错过count方法?这两个回调如何统一获取文档数?

我更愿意坚持使用this 而不是硬编码模型,因为这样可以方便地使用 ES6 类进行模式继承。

【问题讨论】:

    标签: node.js mongodb mongoose


    【解决方案1】:

    您可以使用模型变量的名称代替this

    var mongoose = require('mongoose');
    mongoose.connect('mongodb://localhost/test');
    
    var schema = new mongoose.Schema;
    schema.add({ name: 'string' });
    
    var Cat = mongoose.model('Cat', schema);
    
    schema.pre('save', function (next) {
      Cat.count(function (err, count) {
        if (err) {
          console.log(err)
        } else {
          console.log('there are %d kittens', count);
        }
        next();
      });
    })
    
    var kitty = new Cat({ name: 'Zildjian' });
    kitty.save(function (err) {
      if (err) {
        console.log(err);
      } else {
        console.log('meow');
      }
    });
    

    后续执行会报告正确的计数,然后执行保存操作。

    $ node index.js 
    there are 0 kittens
    meow
    $ node index.js 
    there are 1 kittens
    meow
    $ node index.js 
    there are 2 kittens
    meow
    $ node index.js 
    there are 3 kittens
    meow
    

    并且文档被持久化在数据库中。

    db.cats.find()
    { "_id" : ObjectId("5873b77454fc2a49fd7ec6cf"), "name" : "Zildjian", "__v" : 0 }
    { "_id" : ObjectId("5873b777c051094a0ad5dda2"), "name" : "Zildjian", "__v" : 0 }
    { "_id" : ObjectId("5873b7789aad6e4a15018ee8"), "name" : "Zildjian", "__v" : 0 }
    { "_id" : ObjectId("5873b77b7628684a24c90b07"), "name" : "Zildjian", "__v" : 0 }
    

    【讨论】:

      【解决方案2】:

      实际上this.model 不适用于(pre save hook/middlewarespre.('save'this.model 将适用于updatefindOneAndUpdate 的pre hook ..等

      对于pre.('save' 挂钩,您需要使用this.constructor 而不是this.model,例如:this.constructor.countthis.constructor.findOne 等。

      在我的示例中,假设为 Country

      创建 Schema

      所以你可以像下面这样使用:

      var mongoose = require('mongoose'),
          Schema   = mongoose.Schema;
      
      var CountrySchema = new Schema({
        name: String,
        //....
      });
      
      CountrySchema.pre('save', function(next) {
        var self = this;
        self.constructor.count(function(err, data) {
          if(err){
             return next(err);
          }
          // if no error do something as you need and return callback next() without error
          console.log('pre save count==', data);
          return next();
        });
      });
      
      CountrySchema.pre('update', function (next) {
        var self = this;
        self.model.count(function(err, data) {
          if(err){
             return next(err);
          }
          // if no error do something as you need and return callback next() without error
          console.log('pre update count===', data);
          return next();
        });
      });
      
      module.exports = mongoose.model('Country', CountrySchema);
      

      可以使用mongoose.models['modelName'] like:例如mongoose.models['Country'].count()

      CountrySchema.pre('save', function(next) {
        mongoose.models['Country'].count(function(err, data) {
          if(err){
             return next(err);
          }
          console.log('pre save count==', data);
          return next();
        });
      });
      
      CountrySchema.pre('update', function (next) {
        mongoose.models['Country'].count(function(err, data) {
          if(err){
             return next(err);
          }
          console.log('pre update count===', data);
          return next();
        });
      });
      

      注意:为什么 this.model 不能在 save 的 pre hook 中工作?

      Middleware(也称为 pre 和 post 钩子)是在异步函数执行期间传递控制权的函数。

      在 Mongoose 中有两种类型的中间件:

      1. 文档中间件和
      2. 查询中间件
      1. 文档中间件支持函数。

        initvalidatesaveremove

      2. 查询中间件支持函数。

        count, find, findOne, findOneAndRemove, findOneAndUpdate, insertMany,update

      在 Mongoose 中 查询中间件 this.model 是由 Mongoose 生成/定义的模型实例。在这个中间件this 中返回所有由 mongoose 定义的实例变量

      Document 中间件 this 返回所有 fields 您不是由 mongoose 定义的,所以 this.model 不是您定义的属性。对于上面的例子,我有name 属性,所以你可以通过this.name 得到它,这将显示你的请求值。但是当使用this.contructor 时,您将返回由猫鼬定义的实例变量,如返回Model 实例变量。

      【讨论】:

      • 我希望尽可能坚持使用this。感谢您指向this.constructor。实际上,count 应该是静态方法,所以这是有道理的。我想可能的解释是突出显示的是this.model,看起来它是Model 构造函数,而不是实例(属性名称中的错误大小写无济于事)。
      • 添加了一些解释,据我所知你可以看到@estus
      • 实际上 count 已被弃用 (docs)。您可以使用相同语法的countDocuments()
      猜你喜欢
      • 2015-10-16
      • 1970-01-01
      • 1970-01-01
      • 2015-08-29
      • 2016-09-18
      • 2016-12-15
      • 1970-01-01
      • 1970-01-01
      • 2016-06-07
      相关资源
      最近更新 更多