akaphenom
akaphenom

Reputation: 6888

Mongoose Pre Save hook on Parent Object not executing

I am new to mongoose as a method for updating Mongo. I am using nmap to map my network and provide some visibility on servers and ports that are open (as part of a largeer strategy). This portion of the strategy alos pulls information from CHEF and vSphere which is all linked together in a GUI. Those portions are just simple single level objects and is working fine, however the NMAP portion has a parent/child object model. The object model has a Server object and a Port object - both of which have addedOn and updatedOn dates.

Unfortunately mongoose hook for the pre save is only firing for the children objects (each of them) and not for the parent object - although the parent object is getting saved. I really want the parent object to also have the addedOn and updatedOn dates. I can't seem to figure it out. Thanks in advance

A disclaimer, the code below is snipped out of a larger application written in folktale, ramda and point free form.

NodeJs 5.1, Mongoose 4.4.1

The port.js File

const mongoose = require('mongoose');

const  Schema = mongoose.Schema,
    ObjectId = Schema.ObjectId;

const PortSchema = new Schema({
    id               : ObjectId,
    port             : String,
    protocol         : String,
    application      : String,
    addedOn          : { type: Date, default: Date.now, setDefaultsOnInsert: true },
    updatedOn        : { type: Date, default: Date.now }
});

PortSchema.pre('save', function(next){
    this.update({},{
        $set: {
            updatedOn: new Date()
        }
    })
    next();
});

module.exports.model = mongoose.model('Port', PortSchema)
module.exports.schema = PortSchema

The server.js file

const mongoose = require('mongoose');
const PortSchema = require('./port').schema

const  Schema = mongoose.Schema,
    ObjectId = Schema.ObjectId;

const ServerSchema = new Schema({
    id               : ObjectId,
    address          : String,
    addressType      : String,
    ports            : [PortSchema],
    addedOn          : { type: Date, default: Date.now, setDefaultsOnInsert: true },
    updatedOn        : { type: Date, default: Date.now }
});

ServerSchema.pre('save', function(next){
    this.update({},{
        $set: {
            updatedOn: new Date()
        }
    })
    next();
});


module.exports.model = mongoose.model('Server', ServerSchema)
module.exports.schema = ServerSchema

Upsert code in my application

// nmapUpsert :: (criteria, {}) => Task {ok :: int, ...}
const nmapUpsert = adapt.findOneAndUpdate(Server)


// persist :: [{address :: string, ...}] => [Task {ok :: int, ...}]
const persistNmap = R.map((data) => {
    return nmapUpsert({ "address": data.address }, data)
})

Here is my model -> task upsert adapter (adapt.findOneAndUpdate)

module.exports.findOneAndUpdate = (originalModel) => {
    return (criteria, record) => {

        return new Task((reject, resolve) => {
            const callback = (error, updatedModel) => {
                if (error) {
                    reject(error)
                }
                else {
                    if(!updatedModel) {
                        resolve(null)
                    }else {
                        // this looks to be required to apply defaults from the Schema
                        updatedModel.save((error) => {
                            if (error) {
                                reject(error)
                            }
                            resolve(updatedModel)
                        })
                    }

                }
            }

            originalModel.findOneAndUpdate(criteria, record, {upsert: true}, callback)
        })

    }
}

Admittedly that last function is a bit cludgy - but I am just trying to figure this out before I clean it up.

Upvotes: 2

Views: 1022

Answers (1)

akaphenom
akaphenom

Reputation: 6888

If I change the hooks to findOneAndUpdate I get better behavior. The server objectgets the addedOn on insert (and updatedOn as well), then subsequently just the updatedOn gets updated. Unforutnately the entire Ports object collection gets replaced - even on update - and the addedOn and updatedOn both get updated at that point.

The port.js File

const mongoose = require('mongoose');

const  Schema = mongoose.Schema,
    ObjectId = Schema.ObjectId;

const PortSchema = new Schema({
    id               : ObjectId,
    port             : String,
    protocol         : String,
    application      : String,
    addedOn          : { type: Date, default: Date.now, setDefaultsOnInsert: true },
    updatedOn        : { type: Date, default: Date.now }
});

PortSchema.pre('findOneAndUpdate', function(next){
    this.update({},{
        $set: {
            updatedOn: new Date()
        }
    })
    next();
});

module.exports.model = mongoose.model('Port', PortSchema)
module.exports.schema = PortSchema

The server.js file

const mongoose = require('mongoose');
const PortSchema = require('./port').schema

const  Schema = mongoose.Schema,
    ObjectId = Schema.ObjectId;

const ServerSchema = new Schema({
    id               : ObjectId,
    address          : String,
    addressType      : String,
    ports            : [PortSchema],
    addedOn          : { type: Date, default: Date.now, setDefaultsOnInsert: true },
    updatedOn        : { type: Date, default: Date.now }
});

ServerSchema.pre('findOneAndUpdate', function(next){
    this.update({},{
        $set: {
            updatedOn: new Date()
        }
    })
    next();
});


module.exports.model = mongoose.model('Server', ServerSchema)
module.exports.schema = ServerSchema

Upvotes: 1

Related Questions