Andrew Madonna
Andrew Madonna

Reputation: 155

Mongoose - passing parameters to pre save - does not work in update save

I'm trying to pass a parameter to pre save middleware on a mongoose model like:

subject.save({ user: 'foo', correlationId: 'j3nd75hf...' }, function (err, subject, count) {
    ...
});

It's being passed to two pre save middlewares

First:

schema.pre('save', function (next) {
    // do stuff to model

    if (arguments.length > 1)
        next.apply(this, Array.prototype.slice.call(arguments, 1));
    else
        next();
});

Then:

schema.pre('save', function(next, metadata, callback) {
    // ...
    // create history doc with metadata
    // ...

    history.save(function(err, doc) {
        if(err) throw err;

        if (typeof metadata == 'object')
            next(callback);
        else
            next();
    });
});

It does not work on saving an existing model fetched from the db, but it does work on a newly created model.

It does work if I remove the parameter.

So if I call...

subject.save(function (err, subject, count) {
    ...
});

...it does work.

It looks like the callback never actually calls back. So maybe it's assuming the first parameter is a callback for save() updates.

For create, it does work with passing parameters

(new models.Subject(subjectInfo)).save({ user: user, correlation_id: correlationId }, function (err, subject, count) {
    if (err) throw err;

    ...
});

Any ideas on why it works for save() on create, but not save() on update?

Thanks!!

Upvotes: 2

Views: 9108

Answers (2)

Michael Cole
Michael Cole

Reputation: 16217

After searching and searching, this is what I recommend.

Do the work in a virtual field instead.

schema.virtual('modifiedBy').set(function (userId) {
  if (this.isNew()) {
    this.createdAt = this.updatedAt = new Date;
    this.createdBy = this.updatedBy = userId;
  } else {
    this.updatedAt = new Date;
    this.updatedBy = userId;
  }
});

If that doesn't help you, you might find this other answer helpful: https://stackoverflow.com/a/10485979/1483977

Or this github issue:

https://github.com/Automattic/mongoose/issues/499

Or this.

Upvotes: 5

srquinn
srquinn

Reputation: 10491

model.save() has an arity of 1 and that argument should be the callback function. I'm still not entirely sure how you've got everything setup as the style you've written your code in is a bit foreign. The model's save method can only take the callback like so:

Subject.findOne({ id: id }, function (err, subject) {
  subject.set('someKey', 'someVal');

  // You can only pass one param to the model's save method
  subject.save(function (err, doc, numAffected) {

  });
});

For an update in mongoose, we do:

Subject.update({ id: id}, function (err, numAffected) {
  // There is no doc to save because update() bypasses Subject.schema
});

This link shows where Model.save() is defined. You'll notice it only accepts one argument: https://github.com/LearnBoost/mongoose/blob/3.8.x/lib/model.js#L167

Upvotes: 0

Related Questions