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
Related
I wrote this function to get a document from the end of the collection in MongoDB. When I try calling this function in index.js, it returns undefined.
index.js:
app.get('/', authenticate, function(req, res){
// console.log("DATA: " + getWorldStatsData());
everything = {
worldstats: getWorldStatsData(),
}
res.render('index', {
data: everything
})
})
and my function:
function getWorldStatsData(){
db.collection('worldstats').find({}).sort({"statistic_taken_at":-1}).limit(1).toArray((err, stats)=>{
return stats
})
// return stats
}
As jonrsharpe suggested, this is happening because the code that fetches the data is asyncroous.
That means you need to implement some kind of callback to notify the surrounding function when the operation is complete
A simple example:
index
app.get('/', authenticate, async function(req, res){
// console.log("DATA: " + getWorldStatsData());
everything = {
worldstats: await getWorldStatsData(),
}
res.render('index', {
data: everything
})
})
your funciton:
function getWorldStatsData(){
return db.collection('worldstats').find({}).sort({"statistic_taken_at":-1}).limit(1).toArray((err, stats)=>{
return stats
})
// return stats
}
Please take a look at the link provided by jonrsharpe for a better understanding
i am trying to assign value of a feild from momgoose to a variable which would be used as value to another feild in another schema which is as follows.
function getNextSequence() {
var x = null
relcounter.findOne({"name":"cabi"},'seq', function (err, configs) {
x=configs.seq
console.log("##"+x)
})
console.log(x)
}
X is coming out to be null
Also i need this value of x to add to another feild which is as follows
relconf.update(
{name:"css"},
{ $push: { relations: {id:getNextSequence(),name:req.body.name,divId:"name_div"} } }
Basically ineed the function getNextsequence to return the value of seq feild and assign to id feild
can anyone suggest proper code and reason for null value for getNextSequence()
It useless wrap it in function, you must create include callbacks or Promises chaining. So you need read about asynchronous JavaScript https://www.sitepoint.com/javascript-goes-asynchronous-awesome/ For example:
//callbacks example
...
app.get('/', function(req, res){
//parse request params
...
relcounter.findOne({"name": name},'seq', function (err, configs) {
if(err) {
throw err;
}
res.send(configs.seq);
});
});
//promise example
...
app.get('/', function(req, res){
//parse request params
...
relcounter.findOne({"name": name},'seq')
.then(function(configs){
res.send(configs.seq);
})
.catch(function(err)=>{
throw err;
})
});
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());
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.