17

I need to know modified fields or if a specific field was modified in pre or post update hook in a Mongoose schema. I tried the following, but still unable to figure it out:

schema.post('update', function (doc) {
    //check modified fields or if the name field was modified and then update doc
});

I know maybe there is a method isModified like in pre save but I don't know how to do the same with update hooks. Any suggestions will be appreciated.

jemlifathi
  • 1,482
  • 5
  • 22
  • 32

5 Answers5

14

If you want to know what fields you are modifying, then you need to issue an update command by calling save:

Tank.findById(id, function (err, tank) {
  if (err) return handleError(err);

  tank.set({ size: 'large' });
  tank.save(function (err, updatedTank) {
    if (err) return handleError(err);
    res.send(updatedTank);
  });
});

This way pre-save hook will be invoked and you will be having access to:

Document.prototype.modifiedPaths()

because this in pre-save hook refers to the document:

TankSchema.pre('save', function (next) {
  // ...
  this.modifiedPaths();
  // ...
});

On the other hand, you will not be able to achieve the same result when issuing an update command by calling update:

Tank.update({ _id: id }, { $set: { size: 'large' }}, callback);

because when calling update, document hooks (e.g. pre-save, post-save) are not being executed at all. Instead, query hooks are being executed (e.g. pre-update, post-update) in that case. And the issue with query hooks is that this inside of them does not reference the document, so this.modifiedPaths === undefined

schema.post('update', function (doc) {
  // `this` refers to model.Query
  // `doc` refers to CommandResult 
});
Piotr Kowalski
  • 521
  • 4
  • 14
3

try it:

 schema.post('update', function () {
     const modifiedFields = this.getUpdate().$set;
     // ...
 });
Sajjad Shirazi
  • 2,657
  • 26
  • 24
  • 3
    This is not an answer, whatever fields you throw in $set of update will be listed there, not matter what they are different or same with the old value. – Up209d Oct 25 '19 at 14:33
1

There is no direct way of doing it. There is a variable called isNew which is being tracked by mongoose to check if a new document is created.

see Document#isNew for information on Document#isNew

However, you can created your own tracker to check in post save hook to identify wether document is updated or not.

schema.pre('save', function (doc) {
    this.isDocUpdated = false;
    if (this.isModified()) {
        this.isDocUpdated = true;
    }
});

schema.post('save', function (doc) {
    if (this.isDocUpdated) {
        console.log('post save hook called');
    }
});
Shubham Takode
  • 525
  • 8
  • 24
RiksAndroid
  • 815
  • 11
  • 17
0

For post()

Schema.post('update', function () {
        const modifiedFields = this.getUpdate().$set;
        console.log(modifiedFields);
});

For pre()

schema.pre('update', function () {
        const modifiedFields = this.getUpdate();
        delete modifiedFields['$set'];
        delete modifiedFields['$setOnInsert'];
        console.log(modifiedFields);
});

Erisan Olasheni
  • 2,395
  • 17
  • 20
-1

Have a look at:

http://mongoosejs.com/docs/api.html#document_Document-modifiedPaths

Returns an array of paths modified.

  schema.pre('save', function (next) {
    //check modified fields or if the name field was modified and then update doc
    var modified_paths = this.modifiedPaths();
    next();
  })
Twig2let
  • 27
  • 7
  • It returns `TypeError: doc.modifiedPaths is not a function` There is no function named modifiedPaths in **doc** – jemlifathi Oct 12 '17 at 09:31
  • 1
    My mistake. It appears `modifiedPaths` is not available in the **post** middleware. Have updated the answer. – Twig2let Oct 12 '17 at 15:49
  • 1
    I know there is such function in **pre** **save** hook, but as I mentioned in my question I need to check updated fields in **pre/post update** hook. **comprende?** – jemlifathi Oct 13 '17 at 17:08