Mongoose .pre('save') 不会触发

Posted

技术标签:

【中文标题】Mongoose .pre(\'save\') 不会触发【英文标题】:Mongoose .pre('save') does not triggerMongoose .pre('save') 不会触发 【发布时间】:2015-07-20 09:53:37 【问题描述】:

我有mongoose.model('quotes')的以下型号:

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

var quotesSchema = new Schema(
    created:  type: String, default: moment().format() ,
    type:  type: Number, default: 0 ,
    number:  type: Number, required: true ,

    title:  type: String, required: true, trim: true,
    background:  type: String, required: true ,

    points:  type: Number, default: 1 ,
    status:  type: Number, default: 0 ,
    owner:  type: String, default: "anon" 
);

var settingsSchema = new Schema(
    nextQuoteNumber:  type: Number, default: 1 
);

// Save Setting Model earlier to use it below
mongoose.model('settings', settingsSchema);
var Setting = mongoose.model('settings');

quotesSchema.pre('save', true, function(next) 
  Setting.findByIdAndUpdate(currentSettingsId,  $inc:  nextQuoteNumber: 1  , function (err, settings) 
    if (err)  console.log(err) ;
    this.number = settings.nextQuoteNumber - 1; // substract 1 because I need the 'current' sequence number, not the next
    next();
  );
);

mongoose.model('quotes', quotesSchema);

mongoose.model('settings') 有一个额外的模式来存储递增唯一索引 Quote.number 我试图建立的递增数字。在每次保存之前,都会调用quotesSchema.pre('save') 来读取、增加nextQuoteNumber 并将其作为this.number 分别传递给next() 函数。

但是,当在别处保存 Quote 时,整个 .pre('save') 函数似乎不会触发。 Mongoose 中止保存,因为 number 是必需的,但未定义,并且没有 console.log() 我写入函数输出任何内容。

【问题讨论】:

【参考方案1】:

使用pre('validate') 而不是pre('save') 来设置必填字段的值。 Mongoose 在保存之前会验证文档,因此如果出现验证错误,您的 save 中间件将不会被调用。将中间件从 save 切换到 validate 将使您的函数在验证之前设置数字字段。

quotesSchema.pre('validate', true, function(next) 
  Setting.findByIdAndUpdate(currentSettingsId,  $inc:  nextQuoteNumber: 1  , function (err, settings) 
    if (err)  console.log(err) ;
    this.number = settings.nextQuoteNumber - 1; // substract 1 because I need the 'current' sequence number, not the next
    next();
  );
);

【讨论】:

谢谢。每当实际保存时,我最终只是在我的pre('save') 中执行该操作,因为它最终不会经常发生。我认为如果我不在我的number 上设置required: true,我的变体也会起作用吗? 非常感谢!我有一个未初始化的 required unique 字段,并且尝试预保存挂钩不起作用,直到我像你说的那样切换到验证。【参考方案2】:

我遇到了 pre('validate') 没有帮助的情况,因此我使用了 pre('save')。我读到有些操作是直接在数据库上执行的,因此不会调用 mongoose 中间件。我更改了我的路由端点,它将触发 .pre('save')。我使用 Lodash 解析正文并仅更新传递给服务器的字段。

router.post("/", async function(req, res, next)
    try
        const body = req.body;
        const doc  = await MyModel.findById(body._id);
        _.forEach(body, function(value, key) 
            doc[key] = value;
        );

        doc.save().then( doc => 
            res.status(200);
            res.send(doc);
            res.end();
        );

    catch (err) 
        res.status(500);
        res.send(error: err.message);
        res.end();
    

);

【讨论】:

【参考方案3】:

在某些情况下我们可以使用

UserSchema.pre<User>(/^(updateOne|save|findOneAndUpdate)/, function (next) 

但我在函数内部使用“this”来获取数据,并且不适用于 findOneAndUpdate 触发器

我需要使用

  async update (id: string, doc: Partial<UserProps>): Promise<User | null> 
    const result = await this.userModel.findById(id)
    Object.assign(result, doc)
    await result?.save()
    return result
  

代替

  async update (id: string, doc: Partial<UserProps>): Promise<User | null> 
    const result = await this.userModel.findByIdAndUpdate(id, doc,  new: true, useFindAndModify: false )
    return result
  

【讨论】:

【参考方案4】:

对于被 Google 重定向到这里的人,请确保您在 methods 和挂钩声明之后调用 mongoose.model()

【讨论】:

以上是关于Mongoose .pre('save') 不会触发的主要内容,如果未能解决你的问题,请参考以下文章

Mongoose 是不是提供对 pre('save') 中属性先前值的访问?

Mongoose pre.save() 异步中间件未按预期工作

Mongoose pre.save() 异步中间件未按预期工作

Mongoose 模型的 save() 不会更新空数组

通过 Model.save() 更新时触发 Mongoose 预保存挂钩

文档不会使用带有 mongoose 的 save() 方法保存