Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MongooseJS modify document during pre hook

I'm having some issues with mongoose. My goal is that during pre-save, I would be able to modify the object, doing things like splitting the tags if needed, or in another case calculating the summation of a sub-document durations and update it within the main document.

What I'm finding is that if I load a model, then call doc.update passing the new data, only schema.pre('update', ...) triggers, and any changes to this within my middleware are not updated. I also tried using this.set('...', ....); within my update middleware to no avail.

It seems if I do doc.save(...) instead, then changes to this within schema.pre('save', ...) are appended as expected. Aside from extending the posted variables into my model's properties and saving, I'm not seeing any way of leveraging doc.update for this purpose.

My Goals: - Update an existing document via doc.update(properties, ....) - Use middleware during saving to modify the document, do advanced validation, and update related documents - Use middleware during updating to modify the document, do advanced validation, and update related documents - Interchangeably use model.findByIdAndUpdate, model.save, model.findById->doc.update, model.findById->doc.save and all tap into my save/update middleware.

Some arbitrary sample code:

function loadLocation(c) {
    var self = this;
    c.Location.findById(c.params.id, function(err, location) {
        c.respondTo(function(format) {
            if (err | !location) {
                format.json(function() {
                    c.send(err ? {
                        code: 500,
                        error: err
                    } : {
                        code: 404,
                        error: 'Location Not Found!'
                    });
                });
                format.html(function() {
                    c.redirect(c.path_to.admin_locations);
                });
            } else {
                self.location = location;
                c.next();
            }
        });
    });
}

LocationController.prototype.update = function update(c) {
    var location = this.location;
    this.title = 'Edit Location Details';

    location.update(c.body.Location, function(err) {
        c.respondTo(function(format) {
            format.json(function() {
                c.send(err ? {
                    code: 500,
                    error: location && location.errors || err
                } : {
                    code: 200,
                    location: location.toObject()
                });
            });
            format.html(function() {
                if (err) {
                    c.flash('error', JSON.stringify(err));
                } else {
                    c.flash('info', 'Location updated');
                }
                c.redirect(c.path_to.admin_location(location.id));
            });
        });
    });
};

module.exports = function(compound) {
    var schema = mongoose.Schema({
        name: String,
        address: String,
        tags: [{ type: String, index: true }],
        geo: {
            type: {
                type: String,
            default:
                "Point"
            },
            coordinates: [Number] // Longitude, Latitude
        }
    });
    schema.index({
        geo: '2dsphere'
    });
    var Location = mongoose.model('Location', schema);
    Location.modelName = 'Location';
    compound.models.Location = Location;

    schema.pre('save', function(next) {
        if(typeof this.tags === 'string') {
            this.tags = this.tags.split(',');
        }
    });
};

==== * revised sample * ====

module.exports = function(compound) {
    var schema = mongoose.Schema({
        name: String,
        bio: String
    });

    schema.pre('save', function(next) {
        console.log('Saving...');
        this.bio = "Tristique sed magna tortor?"; 
        next();
    });

    schema.pre('update', function(next) {
        console.log('Updating...');
        this.bio = "Quis ac, aenean egestas?"; 
        next();
    });

    var Author = mongoose.model('Author', schema);
    Author.modelName = 'Author';
    compound.models.Location = Author;
};
like image 982
user1363145 Avatar asked Sep 02 '25 09:09

user1363145


1 Answers

pre hooks work for both doc.save() and doc.update(). In both cases this refers to the document itself.

Note that hooks need to be added to your schema before compiling your model.

schema.pre('save', function(next) {
    if(typeof this.tags === 'string') {
        this.tags = this.tags.split(',');
    }
});
var Location = mongoose.model('Location', schema);
like image 164
aaronheckmann Avatar answered Sep 05 '25 01:09

aaronheckmann