I try to remove object by id , but get error "[TypeError: Cannot read property '$set' of undefined]" what can be wrong?
var remove = function(req, res, next) {
var id = req.urlParams.id ;
req.urlParams.model.findByIdAndRemove(id,function(err, doc){
console.log(err);
if (err) { return sendError(res,err) }
var data = JSON.stringify(req.body);
...
}
id is initialized and object with that id exist
It seems a little strange that you're looking for your mongoose model in the urlParams. I would have expected something more like
function remove(req, res, model, next){
model.findByIdAndRemove(req.params.id, function(err)....
}
I don't know your whole code but, if your goal is remove object that _id has req.urlParams.id, following code would help you.
var remove = function(req, res, next) {
yourModel.remove({_id: req.urlParams.id},function(err, doc){
console.log(err);
if (err) { return sendError(res,err) }
else{ //do something}
}
I have a question : console.log(req.urlParams.id) work?
if you could type your code detail, I can help you more
var id = mongoose.Types.ObjectId((req.urlParams.id).trim());
Related
I am currently studying https://thinkster.io/mean-stack-tutorial/, but am puzzled about the route definition for a child element. For example, in the following...
// create a new comment
router.post('/posts/:post/comments', function(req, res, next) {
var comment = new Comment(req.body);
comment.post = req.post;
comment.save(function(err, comment){
if(err){ return next(err); }
req.post.comments.push(comment);
req.post.save(function(err, post) {
if(err){ return next(err); }
res.json(comment);
});
});
});
... we are trying to define the route for adding a new comment for a particular post. As you can see, we are required to link the parent to the comment...
comment.post = req.post;
... and we are also required to, understandably, save the parent within the comment save function. However, when comes to updating the comment (i.e. increasing the upvotes for a comment) we are only required to do...
// upvote a comment
router.put('/posts/:post/comments/:comment/upvote', function(req, res, next) {
req.comment.upvote(function(err, comment){
if (err) { return next(err); }
res.json(comment);
});
});
... where 'upvote' is a custom schema method...
CommentSchema.methods.upvote = function(cb) {
this.upvotes += 1;
this.save(cb);
};
... why is that we are not required to reference the parent object 'post' here at all? I mean how does the system know exactly which comment to load? I understand that ':post' refers to the parent post, however, we are not even referencing that pre-loaded parent within the method... so how is it being used? Are the correct set of comments automatically loaded from the pre-loaded post parent object, without our need to do this explicitly?
Any guidance would be appreciated.
according with the tutorial :
router.param('post', function(req, res, next, id) {
var query = Post.findById(id);
query.exec(function (err, post){
if (err) { return next(err); }
if (!post) { return next(new Error('can\'t find post')); }
req.post = post;
return next();
});
});
This code will take params from route: post/:post , so basically if you test the route : post/1 , it will set into request object(req) the post with id:1
loopback.getCurrentContext() is null for me. Why? I need to grab the current User from the context. The operation hook's ctx is not the same context and does not contain what I need as far as I can tell.
Customer.observe('before save', function checkPermission(ctx, next) {
//do I have a loopback context that works?
var context = loopback.getCurrentContext();
console.log("context is: " + context);//null!
});
Thanks
I know this question is old but this might help some people
according to loopback doc
https://loopback.io/doc/en/lb3/Using-current-context.html
In LoopBack 2.x, this feature is disabled by default for compatibility reasons. To enable, add
first you need to add this to your customer model
"injectOptionsFromRemoteContext": true
then:
Customer.observe('before save', function checkPermission(ctx, next) {
//ctx.options returns tokenid, userid & ttl
console.log(ctx.options);
return next();
});
This isn't PostgreSQL specific, but it is a bug.
https://github.com/strongloop/loopback/issues/878#issuecomment-128417677
I think you should add a pre-processing middleware to populate the context with the current user.
/server/server.js
app.use(loopback.context());
app.use(loopback.token());
app.use(function setCurrentUser(req, res, next) {
if (!req.accessToken) {
return next();
}
app.models.Customer.findById(req.accessToken.userId, function(err, user) {
if (err) {
return next(err);
}
if (!user) {
return next(new Error('No user with this access token was found.'));
}
var loopbackContext = loopback.getCurrentContext();
if (loopbackContext) {
loopbackContext.set('currentUser', user);
}
next();
});
});
/common/models/customer.js
var loopback = require('loopback');
module.exports = function(Customer) {
Customer.observe('before save', function checkPermission(ctx, next) {
var context = loopback.getCurrentContext();
var currentUser = context && context.get('currentUser');
console.log(currentUser);
next();
});
};
I'm using a generic rest api that allow passing the mongo collection name on the request and serve it's content.
My LIST command looks like that:
router.get('/:collectionName', function(req, res, next) {
req.collection.find().sort('-created_on').exec(function(e, results){
if (e) return next(e);
res.send(results)
});
});
It works great.
My problem is that I want every list query to populate sub objects if exists.
I tried:
req.collection.find().populate().sort..
But obviously I get an error:
TypeError: utils.populate: invalid path. Expected string. Got typeof undefined
Help?
In the end I had to patch it:
router.get('/:collectionName', function(req, res, next) {
var populationQuery = [];
var paths = req.collection.schema.paths;
for (var path in paths) {
if (paths[path].caster) {
populationQuery.push({path: path});
}
}
req.collection.find().populate(populationQuery).sort('-created_on').exec(function (e, results) {
if (e) return next(e);
console.log(results);
res.send(results)
});
});
This works, but I guess there should be some better solution
I am coding a basic project manager, nothing fancy. I am writing the page where the project is created (with AngularJS) and am sending all the $scope to /create (the backend is Express.js). The router gets the JSON perfectly, and save it to a local MongoDB without problems.
My problem is that I want to set a message telling that the project was created successfully and send it back to AngularJS. This is my code.
router.js
module.exports = function(app, db) {
app.post('/create', function (req, res) {
var create = require("./../scripts/create")(req, res, db);
console.log(create); //just for testing whether I can receive the message.
});
}
create.js
module.exports = function(req, res, db) {
db.collection('projects').insert(req.body.project, function(err, docs) {
if (err) throw err;
return 'Project created.'; //I want to return this string.
});
};
I don't know how to return something from inside the db.collection.insert's callback function.
So you have to remember that anonymous function calls in JavaScript are not assigned to anywhere. They are passed, and then lost. This is usually why we don't really have return statements in them.
var x = function () { return y }; gives x the value of y but since there is never an assignment of the value of a callback, a return statement is meaningless. Callbacks, no matter if they have a return value, will not give you a value. They may feed that return value up to the function that they were given to, but they are entirely lost to you.
The way to get around this is to do some trickery with the scope. Basically what you want to do is 'bump' the value you want to return up a scope you can assign and then return it there. For example, you can do this:
module.exports = function(req, res, db) {
var stringToReturn;
db.collection('projects').insert(req.body.project, function(err, docs) {
if (err) throw err;
stringToReturn = 'Project created.'; //I want to return this string.
});
return stringToReturn;
};
This will work because the return value gets bound to module.exports, which is in turn bound to the result of
var create = require('./create');
console.log(create('something')) //should log 'Project created.'
Solved!!
Router.js
module.exports = function(app, db) {
app.post('/create', function(req, res) {
var create = require("./../scripts/create")(req, res, db);
});
});
Create.js
module.exports = function(req, res, db) {
db.collection('projects').insert(req.body.project, function(err, records) {
if (err) throw err;
res.send("Project created.");
});
};
Now Angular is receiving the response from the server.
and thanks to be there.
Issue :
I'm making a tiny mongoose "middleware" to handle a mongoose error :
// callback function called at each mongoDB response
var handleDbRes = function(callback) {
return function (err, entries) {
if (err) {
err.status = 500;
return next(err);
}
return callback(entries) // that line throw the exception
}
};
And so I'm using it into an api endpoint, e.g. :
someRouter.get('/', function(req, res) {
models.article.find(handleDbRes(res.json))
})
With that code, I encounter an error :
TypeError: Cannot call method 'get' of undefined
I followed the exception and looked at res.json() declaration, when debugging, I figured out :
var app = this.app;
var *** = app.get('***') // that line throw the exception
I guess that app is not defined cause app doesn't exists in "this".
Please can you help me to solve this problem ? I think that the reason is simple but I don't get it...
Thanks you for listening ;)
EDIT : I tried to res.json.bind(res) and it worked, as I thought, but that's really awful to bind this way for most api endpoint and I guess there is another way to do that kind of functionality without that.
EDIT : Thanks to Mscdex advices, I modified my code this way :
.get('/', function(req, res, next) {
models.article.find(handleDbRes(res.json.bind(res), next))
...
...
// callback function called at each mongoDB response
var handleDbRes = function(successCallback, errorCallback) {
return function (err, entries) {
if (err) {
err.status = 500;
return errorCallback(err);
}
return successCallback(entries)
}
};
When you pass res.json, the context for the json() function is lost (it no longer knows what this is because it is not bound). So here are a few possible solutions:
Use a bound version of the function so that this inside json() will always evaluate correctly:
someRouter.get('/', function(req, res) {
models.article.find(handleDbRes(res.json.bind(res)))
})
Or use a wrapper function instead:
someRouter.get('/', function(req, res) {
function respondJSON(val) {
res.json(val);
}
models.article.find(handleDbRes(respondJSON))
})
Or just pass in res and call res.json() inside handleDbRes():
someRouter.get('/', function(req, res) {
models.article.find(handleDbRes(res))
})
// callback function called at each mongoDB response
var handleDbRes = function(res) {
return function(err, entries) {
if (err) {
err.status = 500;
return next(err);
}
res.json(entries);
}
};
The other problem is that handleDbRes() doesn't have access to next, so you need to also pass that function in for when you run into an error.