Reputation: 6888
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
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