Add a method to Express model - node.js

Let's suppose I have an Express model:
var SchemaDescription = {};
var Model = = new mongoose.Schema(SchemaDescription);
Express allows to tune up data validation in SchemaDescription. On save it works perfectly, but on update, because of mongoose nature, it isn't called, and there is no clean way to call it.
I tried Model.pre('update', ...); but didn't found the way to access/correct model's data before writing to the DB: because complex validation logics, which, for example, re-formats some data before checking.
A logical solution is to put validation code to save/update controller's handlers, but it leads to duplication of the code. To keep MVC pattern as for save, as for update, I'd like to put a public method to the model, or the schema, which gets input data and validate them.
My attempts look like:
Model.prototype.validate = function(input, isUpdate) {...};
or
SchemaDescription.validate = function(...) {...};
in different combinations.
The response always looks like "Cannot set property 'validate' of undefined"
Is there an approach to put a custom public function-member to an Express model/schema for being called in controllers?
What approach may be used to validate data on save and update, without code duplication, or/and putting validation logics to controllers?

You don't have an Express model, you have a Mongoose model. According to the latest documentation, you can explicitly activate validation on update: http://mongoosejs.com/docs/validation.html#update-validators

Related

mongoose optimistic concurrency - how to track changes on document when versioning error handling is needed

we have a big enterprise Node.JS application with multiple microservices that can in parallel access DB entity called context. At some moment we started to have concurrency issues, i.e. two separate microservices did load same context, did different changes and saved, resulting in loss of data. Because of this we have rewritten our DB layer to use mongoose with full optimistic concurrency enabled (via scheme option optimisticConcurrency). This work fine and now when we get version error we reload latest version of the context, reapply all the changes again and save. Problem is that this reapplication creates duplicities in code. Our general approach can be expressed by following pseudo code:
let document = Context.find(...);
document.foo = 'bar'
document.bar = 'foo'
try {
document.save()
} catch(mongooseVersionError) {
let document = Context.find(...);
// DUPLICATE CODE HERE, DOING SAME ASSIGNMENTS (foo, bar) AGAIN!
document.foo = 'bar'
document.bar = 'foo'
document.save()
}
What we would like to use instead is some automated tracking of all changes on document so that when we get mongoose versioning error we can reapply these changes automatically. Any idea how to do it in most elegant way? Does mongoose support something like this out of the box? I know that we could check in presave hook document attributes one by one via Document.prototype.isModified() method but this seems to me like quite worky and unflexible approach.

Verify Joi validation was added to hapi route

I am reusing a Joi schema in multiple places in my code and I would like to find a clean way to test that my endpoints are assigned the validation schema. This would be helpful since I could verify the schema behaved the way I expect without having to repeat the same series of tests everywhere the schema is used.
If I have a hapi server route:
server.route({
method: POST,
path: 'myUrl',
config: {
validate: {
payload: validation.myJoiValidation,
}
}
})
how would I test that the validation.myJoiValidation object has been assigned to the config.validate.payload element?
I dug down into the hapi request object and found that what I am looking for is located in the request.route.settings.validate.payload._inner.children object, but I really don't want to have to rely on that for what I am trying to do.
If you have a server running in the context of your test, you can get the validation schema being used with:
const schema = server.match('post', 'myUrl').settings.validate.payload;
Schemas can't be directly compared (as with Hoek.deepEqual), but they can be compared by using joi.describe, so:
expect(joi.describe(schema)).to.equal(joi.describe(validation.myValidation));
Or, if you are using mocha/chai I think this would be:
expect(joi.describe(schema)).to.deep.equal(joi.describe(validation.myValidation));
In your unit tests make a request with request or similar package with a payload that doesn't pass the validation. Ensure the response code is a 400.
Example test from a project of mine. It tests a regex Join validation on this route. This uses a small promise wrapper around request called yarp.

Creating/saving Loopback model programmatically

I am trying to use
// item is some string representing model name
const Model = app.models[item];
Model.create([array of model data],{options}, function(a, b, c){
});
but this API is giving me hell, it seems to fire the callback inconsistently if at all, and also, {a,b,c}, seem to be totally inconsistent, in other words, Model.create does not seem to fire a standard error first callback and I simply cannot figure out what it is passing back, seems to be very inconsisent.
I filed an issue on Github for Loopback on this, but I am wondering if there is a better API for programmatically creating models like this.
I am trying to seed our test database with data.
There is no second optional parameter.
Model.create({propA: value /*, etc */}, function(err, results){
});

Is it correct to change fields in pre('validate') middleware in mongoose?

I need to generate slug every time that post get saved into database. Specifficallly on Post.create and post.save. The single place where I may need this in PostShema.pre('validate') middleware like the following:
PostSchema.pre('validate', function (next) {
this.slug = sluglify(this.title);
return next();
});
All works fine except the fact that it happens in validate middlweare that should only check but not set.
SO my questuin is where should I reside my code for sluglify my title on creating or updating post?
This is not happening in the validation but before the validation. IMHO, it 's like if you are prepearing/cleaning your object before validating it; which is OK.
If you feel more confortable with that you could include it in a pre-save or pre-init instead of the pre-validate

Extending MongoDB's "save" method in nodejs

In our app, we have a large document that is the source of most of our data for our REST api.
In order to properly invalidate our client-side cache for the REST api, i want to keep track of any modifications made to teh document. The best we came up with is to extend the mongo save command for the document to send off the notification (and then save as usual).
The question is, how does one actually do this in practice? Is there a direct way to extend mongo's "save" method, or should we create a custom method (i.e. "saveAndNotify") on the model that we use instead (which i would avoid if i can)?
[edit]
So in principle, i am looking to do this, but am having an issue not clobbering the parent save function();
mySchema.methods.save = function() {
// notify some stuff
...
//call mongo save function
return this.super.save();
};
Monkey patching the core mongo object is a bad idea, however it turns out mogoose has a middleware concept that will handle this just fine:
var schema = new Schema(..);
schema.pre('save', function (next) {
// do stuff
next();
});

Resources