I have Mongoose model updated and then retrieved with $inc
operator that implements simple view counter:
const profile = await Profile.findOneAndUpdate({ userName }, { $inc: { viewsCount: 1 } });
Profile
schema has timestamps
option enabled. The problem is that updatedAt
is updated during viewsCount
update, this is not a desirable behaviour.
I would like to to disable updatedAt
updates when viewsCount
is updated, preferably by doing as few queries as possible.
I assume that Mongoose timestamps are implemented with pre-hooks.
How can findOneAndUpdate
increment viewsCount
without updating updatedAt
?
Can this be done by negating the effect of timestamp hook?
There are similar questions that address the problem with updatedAt
updates but solutions don't suit the case.
As the name implies, findOneAndUpdate() finds the first document that matches a given filter , applies an update , and returns the document. By default, findOneAndUpdate() returns the document as it was before update was applied. You should set the new option to true to return the document after update was applied.
By default, if you don't include any update operators in doc, Mongoose will wrap doc in $set for you. This prevents you from accidentally overwriting the document.
Mongoose | update() Function The update() function is used to update one document in the database without returning it.
A Mongoose model is a wrapper on the Mongoose schema. A Mongoose schema defines the structure of the document, default values, validators, etc., whereas a Mongoose model provides an interface to the database for creating, querying, updating, deleting records, etc.
Starting with mongoose 5.9.3, you can set the third parameter to { timestamps: false }
.
From the docs:
[options.timestamps=null] «Boolean» If set to false and schema-level timestamps are enabled, skip timestamps for this update. Note that this allows you to overwrite timestamps. Does nothing if schema-level timestamps are not set.
After scouring the Mongoose documentation, it appears that the short answer is no, there is no way to call findOneAndUpdate()
without the updatedAt
field being set. If you view the docs here, it clearly states that all of the functions for updating (findOneAndUpdate(), update() and bulkWrite()) add the $set
operator to the query to set updatedAt
. That being said, you do have another option which I would highly recommend.
Work Around
Add the createdAt and updatedAt fields directly to your models, and get rid of the timestamps. Sure, it's really nice that Mongoose handles it for you, but in the end, if you have to try and change the set functionality of the timestamps for a specific use case, it would be better to do it on your own.
If you enjoy having the updatedAt and createdAt set when you call .save()
or .update()
, you can always write your own middleware to add in the operations.
ProfileSchema.pre('save', function(next) {
this.createdAt = Date.now();
this.updatedAt = Date.now();
next();
});
I understand this isn't the desired solution, but quite frankly I find it more useful since have greater control, and less unexpected behavior from Mongoose. The more control you have over your own code, the better. Hope this helps!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With