[using mongoose v4.0.7]
Is it possible to modify the this._update object in pre-middleware? I have some middleware set up to transform a certain field if present in the update and i've found that if the field is in the top-level of the update object, the transformed value is stored, but if the value is in a $set command, the untransformed value is stored. To illustrate:
UserSchema.pre('update', function(next) {
var update = this._update;
if (update.$set && update.$set.name) {
// this does not work...whatever was originally in update.$set.name is saved
update.$set.name = transform(update.$set.name);
} else if (update.name) {
// this works...the transformed name is saved
update.name = transform(update.name);
}
next();
})
Is this expected? I've noticed that I can do this to make it work:
if (update.$set && update.$set.name) {
update.name = transform(update.$set.name);
}
but it seems that this would limit my ability to make adjustments in middleware for $push, $inc, etc operations.
Possibly related to issue #3024
The below script works in 4.1.5, looks like #3024 may have fixed this. The update op should always be under $set
in pre-update middleware, mongoose handles that casting when you call .update()
but before the hooks happen.
var assert = require('assert');
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/gh3303');
mongoose.set('debug', true);
var UserSchema = new mongoose.Schema({
name: String,
test: String
});
UserSchema.pre('update', function(next) {
var update = this._update;
if (update.$set && update.$set.name) {
this.update({}, { name: transform(update.$set.name) });
}
next();
});
var User = mongoose.model('gh3303', UserSchema);
User.update({}, { name: 'abc', test: 'abc2' }, function(error) {
assert.ifError(error);
User.update({}, { $set: { name: 'abc', test: 'abc2' } }, function(error) {
User.update({}, { $set: { test: 'abc2' } }, function(error) {
process.exit(0);
});
});
});
function transform(str) {
return str.toUpperCase();
}
I get the expected queries:
$ node gh-3303.js
Mongoose: gh3303.update({}) { '$set': { test: 'abc2', name: 'ABC' } } {}
Mongoose: gh3303.update({}) { '$set': { name: 'ABC', test: 'abc2' } } {}
Mongoose: gh3303.update({}) { '$set': { test: 'abc2' } } {}
There should be no need to update the _update
object directly (and its very much recommended that you do that), just use this.update()
.
Looks like this works, so I'm gonna close it. Re-open if this is still an issue in 4.1.x
@vkarpov15 I did the same thing you did but this results in two update queries for same document. One is the normal update and other one is in pre. This is how i did it #4389
Most helpful comment
The below script works in 4.1.5, looks like #3024 may have fixed this. The update op should always be under
$set
in pre-update middleware, mongoose handles that casting when you call.update()
but before the hooks happen.I get the expected queries:
There should be no need to update the
_update
object directly (and its very much recommended that you do that), just usethis.update()
.Looks like this works, so I'm gonna close it. Re-open if this is still an issue in 4.1.x