I want to update last inserted/updated document(row) in "after save" hook without create new instance of that like this:
Model.observe('after save', function (ctx, next) {
ctx.someProperty = 'Foo';
ctx.update();
});
How it possible?
I'm not sure what you mean by 'update' a model. As far as I know, there is no update() function on the generic model class. If you're looking for updateAttribute then the documentation on that functionality is here.
However, assuming your question is just "How do I access the observed model inside of a loopback hook?" then the answer is that the instance is stored at ctx.instance rather that returned as ctx variable itself. See the examples here.
E.g.
Model.observe('after save', function (ctx, next) {
ctx.instance.updateAttributes({someProperty: 'Foo'})
});
If you can describe in more detail the functionality you're trying to achieve with the update() function, I will try to address that question. Note also that the code above would probably cause an infinite loop - because the updateAttribute call will itself trigger the 'after save' hook - which is another reason why I'm not so sure what you're really asking.
Related
I'm reading the GitHub https://github.com/goldbergyoni/nodebestpractices and trying to apply the tips on my project. Currently i'm working on the "1.2 Layer your components, keep Express within its boundaries" tip, but I have a question.
I'm using routes/controllers, and using this tip (1.2), a route with multiple middlewares will look like this.
router.post("/do-multiple-stuff",
(req, res, next) => {
stuffController.getStuffDone(req.body.stuff);
next();
},
(req, res, next) => {
stuffController.getOtherStuffDone(req.body.otherStuff);
return res.send("stuff done");
});
Is this correct? Or there's a better way to do this?
Thanks! <3
The point of that 1.2 section is to create your business logic as a separate, testable component that is passed data only, not passed req and res. This allows it to be independently and separately tested without the Express environment around it.
Your calls to:
stuffController.getStuffDone(req.body.stuff);
and
stuffController.getOtherStuffDone(req.body.otherStuff);
Are indeed making that proper separation between the web and the business logic because you aren't passing req or res to your controller. That looks like it meets the point of the 1.2 training step.
The one thing I see missing here is that there isn't any output from either of these function calls. They don't return anything and since you don't pass req or res to them, they can't be modifying the req object (like some middleware does) and can't be sending a response or error by themselves. So, it appears that these need a mechanism for communicating some type of result back, either a direct return value (if the functions are synchronous) or returning a promise (if the functions are asynchronous). Then, the calling code could get their result and do something with that result.
In loopbackjs the follow api not working.
PUT /Bookstore/{id}/books/rel/{fk} Add a related item by id for books.
I define in phase of boot
app.remotes().before('*.*', inject);
app.remotes().before('*.prototype.*', function(ctx, instance, next) {
inject(ctx, next);
});
function inject add to options more information.
But in this case the first operation is
Model.observe('access',.... define in mixin and not inject.
The api fail.
Someone has already had the same problem?
Using Loopback framework, I want to perform some operations before the Item is edited hence I am trying this but unable to bind this to the update hook.
Item.beforeRemote("update", function(ctx,myitem,next) {
console.log("inside update");
});
Instead of update I have tried with updateAttributes,updateById, create but none works. This kind of beforeRemote hook works well with create on POST, but unable to get it with PUT during edit.
The last solution left with me is again inspect the methodString with wildcard hook but I want to know if there is anything documented which I could not find.
Item.beforeRemote("**",function(ctx,instance,next){
console.log("inside update");
});
I know that two year have passed since this post was opened, but if any body have the same question and if you use the endpoint your_model/{id} the afterRemote hook is replaceById.
If you need to know which method is fired in remote hook use this code:
yourModel.beforeRemote('**', function(ctx, unused, next) {
console.info('Method name: ', ctx.method.name);
next();
});
Contrary to the comments, save is a remote hook, not an operation hook, but you want to use it as: prototype.save. The relevant operational hook would be before save. You can see a table of these on the LoopBack docs page. I would probably implement this as an operational hook though, and use the isNewInstance property on the context to only perform the action on update:
Item.observe('before save', function(ctx, next) {
if (ctx.isNewInstance) {
// do something with ctx.currentInstance
}
next();
});
Sorry for bumping into old question but its for those who are still searching.
'prototype.updateAttributes' can be used as remote hook for update requests.
and #jakerella , there is no remote hook called 'save' , i myself tried it, but didnt work.
Came here looking for another thing, guess it will be helpful to someone.
For before remote model/:id patch method you have to use "prototype.patchAttributes".
On loopback3 for PATCH you can use "prototype.patchAttributes" to sanitize your data before the update.
YourModel.beforeRemote('prototype.patchAttributes', (ctx, unused, next) => {
console.log(ctx.args.data);
next();
});
everyone ! I've this sentence in my app.js:
app.get('/aux/:subject/:data', aux.query);
app.post('/register/:Id', register.create);
app.post('/register/:Id/smsConfirm', register.confirmSms);
app.post('/register/:Id/login', register.login);
app.post('/register/:Id/resetPassword', register.resetPassword);
app.get('/register/:Id/getSms', register.getSms);
And I will have much more because it's the beginning. And i'd like to implement a global function to be executed before any class like aux.query, register.create, etc be invoked.
Basically I'd like to check if the IP is on my black list. If true: Don't execute anything - Throw a 403 instead.
Actually the only way I know to implement this is to put in any method a verification using promises and after check, allow the execution, but I believe that there is a better way to do the things in a global way (maybe not ??)
Can someone give me a good hint ? ty !
You should handle your black list check as middleware if it is a valid test for every endpoint.
function blacklist(req, res, next) {
// check blacklist
// call next() if passed
next();
}
app.use(blacklist);
app.get('/aux/:subject/:data', aux.query);
app.post('/register/:Id', register.create);
app.post('/register/:Id/smsConfirm', register.confirmSms);
app.post('/register/:Id/login', register.login);
app.post('/register/:Id/resetPassword', register.resetPassword);
app.get('/register/:Id/getSms', register.getSms);
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();
});