Understanding markModified() in MongooseJul 29, 2020
Have you ever come across a scenario where your model.save() on your mongoose wasn't updating the record on the database? And was the field you were trying update is an array of mixed types?
According to Mongoose documentation, Mixed is a schema-less type, you can change the value to anything else
you like, but Mongoose loses the ability to auto detect and save those
changes. To tell Mongoose that the value of a Mixed type has changed, you
need to call doc.markModified(path), passing the path to the Mixed type you
just changed. -
In order to update our array column to DB, we have to understand two things
- We need to know how mongoose is detecting the column changes
- How mongoose is saving the document when we call the model.save() method
Whenever, you try to set any value to mongoose model like model.banks =  then mongoose's $__set method will be called. This in return calls the $__shouldModify method where mongoose checks the data types of the schema and returns either true or false. If you check the content of this method, it internally calls the deepEqual method. This is exactly where the match happens between the DB schema and the field's schema that we're trying to update. In here, you can clear see that mongoose isn't trying to check the data types of Array, because of which it will return false and also since no condition was matched on __shouldModify method, that too will return false and hence our Array column will be ignored without being updated.
Whenever we call the model.save() method, mongoose calls the $__handleSave() function from $__save() and inside that, it validates whether the request is new or existing one. If it is existing one, then it calls the $__delta function, which in return calls $__dirty() method. Here, $__dirty returns the modified columns compared with an existing document records on DB level. Please note that, under Point 1 : Detecting Changes we're simply detecting the database schema data types and where, as here, we're checking the value of the column and both are different functionalities altogether. So, if there is way to make mongoose know that we have modified our array column then that would solve our problem. This is where model.markModified() comes to our rescue.
Inside of $__dirty function, you could see this.$__.activePaths which holds the list of modified columns. So, when you call model.markModified(), it manually sets the array column that we are trying to update as modified and this makes mongoose detect the column change and updates the DB.
That's it! To sum up, when you try to set a new value to one of the mongoose's columns, it first validates the data type and ignores them if it is of type Array with mixed data type thus your new value will not be persisted on DB. So, in order to make it persisted on DB level, mongoose offered us a handy method called markModified() which manually marks a particular column as modified and make mongoose to update the DB accordingly.
Hope you got the hang of it. See you in another article. Happy Coding!