Stanley
Stanley

Reputation: 135

How do I use a pre save hook database value in Mongoose?

I want to get the value of an object before the pre-save hook and compare that to the new value. As suggested in mongoose get db value in pre-save hook and https://github.com/Automattic/mongoose/issues/2952, I did a post-init hook that copied it to a doc._original. The issue is that I'm not sure how to access this ._original in a different hook.

FieldSchema
  .post('save', function (doc) {
    console.log(doc._original);
  });

FieldSchema
  .post('init', function (doc) {
    doc._original = doc.toObject();
  });

I know that the doc in the post save hook is different from the doc in the post init hook, but how would I access the original?

Upvotes: 1

Views: 6875

Answers (1)

laggingreflex
laggingreflex

Reputation: 34627

You can only access properties on a database which you have defined in its schema. So since you probably haven't defined _original as a property in your schema, you can't access, or even set it.

One way would be to obviously define _original in your schema.

But to get and set properties not defined in your schema: use .get, and .set with {strict:false}

FieldSchema
  .post('save', function (doc) {
    console.log(doc.get('_original'));
  });

FieldSchema
  .post('init', function (doc) {
    doc.set('_original', doc.toObject(), {strict: false});
  });

Note the option {strict: false} passed to .set which is required because you're setting a property not defined in the schema.


update:

First thing I didn't notice before is that in your question title you want pre-save hook but in your code you actually have a post-save hook (which is what I based my answer on). I hope you know what you're doing, in that post save hook is invoked after saving the document.

But in my opinion, and from what I can understand what your original intent was from the question, I think you should actually use a pre-save hook and an async version of it (by passing next callback), so that you can .find (retrieve) the document from the database, which would be the original version since the new version hasn't yet been saved (pre-save) thus enabling you to compare without actually saving any new fields, which seems an anti-pattern to begin with.

So something like:

FieldSchema
  .pre('save', function (next) {
    var new_doc = this;
    this.constructor   // ≈ mongoose.model('…', FieldSchema).findById
      .findById(this.id, function(err, original){
        console.log(original);
        console.log(new_doc);
        next();
      });
  });

http://mongoosejs.com/docs/middleware.html

Upvotes: 5

Related Questions