node.jsmongodbexpressmongoose

Mongoose .pre('save') does not trigger


I have the following model for 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);

There is an additional Schema for mongoose.model('settings') to store an incrementing number for the incrementing unique index Quote.number im trying to establish. Before each save, quotesSchema.pre('save') is called to read, increase and pass the nextQuoteNumber as this.number to the respectively next() function.

However, this entire .pre('save') function does not seem to trigger when saving a Quote elsewhere. Mongoose aborts the save since number is required but not defined and no console.log() i write into the function ever outputs anything.


Solution

  • Use pre('validate') instead of pre('save') to set the value for the required field. Mongoose validates documents before saving, therefore your save middleware won't be called if there are validation errors. Switching the middleware from save to validate will make your function set the number field before it is validated.

    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();
      });
    });