I am trying to create a model then create another model and save the reference to the original model using mongoose. I have been looking through mongoose's documentation on middleware and their hooks, but some of those don't seem to fire.
This answer tells me why my init hook would not fire HERE, pre
and post
init
only fire when loading a pre existing model from the db. So I read that validate
would run on the creation of a new model. In knowing that I switched from pre
init
to pre
validate
.
Here is the code for what I am trying to do:
GroupSchema.pre('validate', function (next, data) {
console.log("inside pre validate");
if (data.location) {
location = new Location(data.location);
data.location = location._id;
location.save(function (err) {
if (err) handleError(err);
});
}
next();
})
I know I can't use this
because the document is not populated with data yet. So that is why I have data
, but this still does not seem to work, oh I got which parameters I am supposed to pass in from this answer.
Any help would be appreciated.
**************UPDATE**************
To add some clarity, using what was recommended in an answer and changing my pre
validate
function to this:
GroupSchema.pre('validate', function (next, data) {
console.log("inside pre validate", this);
if (this.location) {
location = new Location(this.location);
this.location = location._id;
location.save(function (err) {
if (err) handleError(err);
});
}
next();
})
I get the following error
service err: CastError: Cast to ObjectId failed for value "[object Object]" at path "location"
Which makes sense because in my model it expects an ObjectId
and not [object, Object]
which is what I am passing. However, I thought I could save the location
, get the ObjectId
that was generated and store that in the group model before it threw an error. Hence originally using pre
init
until finding out that wouldn't work and now find out that pre
validate
will also not work. Is there any way to do what I am trying?
Here is what I am trying in sequence:
ObjectId
ObjectId
in the group instead of the Object itselfreason I was trying to add this to a pre
hook is so that I could have this code in one spot and it automatically would handle this when newing up a group model.
pre('save', function(next) { // do stuff next(); }); In mongoose 5. x, instead of calling next() manually, you can use a function that returns a promise. In particular, you can use async/await .
On my journey to explore MongoDB and Mongoose's powerful features over the years, I encountered something called pre and post hooks, few years back. They are simple yet powerful tools with which you can manipulate model instances, queries, perform validation before or after an intended database operation etc.
Mongoose has several built-in validators. All SchemaTypes have the built-in required validator. The required validator uses the SchemaType's checkRequired() function to determine if the value satisfies the required validator. Numbers have min and max validators.
Pre- and post-execution hooks are Processing scripts that run before and after actual data processing is performed. This can be used to automate tasks that should be performed whenever an algorithm is executed.
What you're trying to do isn't a good fit for validate
or any other middleware, because you have a need to supply location data along with what's needed to create the group itself.
A better fit would be to create a static method on GroupSchema
that explicitly performs this enhanced create function.
So assuming basic location and group schemas like:
var LocationSchema = new Schema({
city: String,
state: String
});
var GroupSchema = new Schema({
name: String,
location: {type: ObjectId, ref: 'Location'}
});
Add a static method to the group schema and register the models:
GroupSchema.statics.createWithLocation = function(group, location, callback) {
Location.create(location, function(err, location) {
if (err) return callback(err);
group.location = location._id;
Group.create(group, callback);
});
};
var Location = mongoose.model('Location', LocationSchema);
var Group = mongoose.model('Group', GroupSchema);
Call the new method by separately passing the group and location data parameters:
Group.createWithLocation(
{name: 'group1'},
{city: 'New York', state: 'NY'},
function(err, group) {
console.log('group created with location: ', group);
}
);
pre(validate) triggers before a ".save" and do note that data does not have the current document.The "this" variable will have it.Also note .pre(validate) will trigger whenever we do ".save".Here below is an example of how to do what you are looking for.I worked it out and it works perfectly.
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
//group schema
var GroupSchema = new Schema({
location: String,
pass: String
});
//dependant location schema
var LocationSchema = new Schema({
city: String
});
//here I compile it into a model -groupschema
var Groupuser = mongoose.model('usertest', GroupSchema, 'usertest');
//here I compile it into a model-location schema
var Location = mongoose.model('locationtest', LocationSchema, 'locationtest');
//here is the pre validate,note this will trigger when we save groupschema realted documents.
GroupSchema.pre('validate', function(next, data) { //will be triggered before the save
console.log("inside pre validate", this); //the this will have amsterdam,and test see below.
if (this.location) {//will be amsterdam
var location = new Location();
location.city = this.location//adding amsterdam to the location.city
location.save(function(err, data) {//this data will have the location document that we just saved.
});
}
next();
});
//now I create a new user for groupschema
var newuser = new Groupuser();
newuser.location = 'amsterdam';
newuser.pass = 'test'
newuser.save(function(err) { //Before this save function does the save,it triggers the .pre(validatE)
if (err) return console.log(err);//
});
I might have not nailed the inner location functionality as you want,but I am sure .pre(validate) triggers only when you do .save. It can be a new document or an existing doucment.Also note that it does not trigger when loading a model.
1)we define a schema (var schema=new Schma({datatypes})
2)we compile it into a model(var model=mongoose.model('collectionname',schema)
3)we instantiate a new variable of the model(var user=new model(); and then define the values
4) finally we save the data(user.save()->its here that the pre.validate triggers
Hope its clear now
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