How to get a callback on MongoDB collection.find() - node.js

When I run collection.find() in MongoDB/Node/Express, I'd like to get a callback when it's finished. What's the correct syntax for this?
function (id,callback) {
var o_id = new BSON.ObjectID(id);
db.open(function(err,db){
db.collection('users',function(err,collection){
collection.find({'_id':o_id},function(err,results){ //What's the correct callback synatax here?
db.close();
callback(results);
}) //find
}) //collection
}); //open
}

That's the correct callback syntax, but what find provides to the callback is a Cursor, not an array of documents. So if you want your callback to provide results as an array of documents, call toArray on the cursor to return them:
collection.find({'_id':o_id}, function(err, cursor){
cursor.toArray(callback);
db.close();
});
Note that your function's callback still needs to provide an err parameter so that the caller knows whether the query worked or not.
2.x Driver Update
find now returns the cursor rather than providing it via a callback, so the typical usage can be simplified to:
collection.find({'_id': o_id}).toArray(function(err, results) {...});
Or in this case where a single document is expected, it's simpler to use findOne:
collection.findOne({'_id': o_id}, function(err, result) {...});

Based on JohnnyHK answer I simply wrapped my calls inside db.open() method and it worked. Thanks #JohnnyHK.
app.get('/answers', function (req, res){
db.open(function(err,db){ // <------everything wrapped inside this function
db.collection('answer', function(err, collection) {
collection.find().toArray(function(err, items) {
console.log(items);
res.send(items);
});
});
});
});
Hope it is helpful as an example.

Related

What is the best way to query mongodb with mongoose with an array of IDs?

I query one collection (messages) with mongoose. The result is an array of documents. Each document contains an ID for a different collection (users). Now I want to query the users collection for each ID from the messages collection.
The idea is to update each message object with the information from the user collection before returning it to the front end.
I tried using async.each. For some reason the final function is never called even though I am making sure the callback() function is called after each iteration.
app.get('/getmsg', function(req, res){
messages.find({query})
.exec(function(err, ms){
if(err) throw err;
async.each(ms, function(m, callback){
users.findOne({_id : m.userId})
.lean()
.exec(function(err, user){
if(err) {
console.log('error' , err);
callback();
} else {
m.userName = user.name;
// everything is working up to here
callback();
}
}), function(err){
res.send(ms); // this is never returned!
}
});
});
});
Is there a better way of achieving this? I assume this must be a common issue.
Thanks!
You can't use res.send. Instead create a function to get notified about it. Something like this.
// 1st para in async.each() is the array of items
async.each(items,
// 2nd param is the function that each item is passed to
function(item, callback){
// Call an asynchronous function, often a save() to DB
item.someAsyncCall(function (){
// Async call is done, alert via callback
callback();
});
},
// 3rd param is the function to call when everything's done
function(err){
// All tasks are done now
doSomethingOnceAllAreDone();
}
);

Sails js -model resultset variable scope

Can someone explain to me why i can't save the booksCount variable into the users json object? Here's my code
for(var user in users){
Books.count({author: users[user]['id']}).exec(function(err, count){
users[user]['booksCount']=count;
});
}
return res.view('sellers', {data: users});
Where Users is the list of users from the table which is the direct result of a User.find() method. User is the model.
Now if i try to print the users[user]['booksCount'] inside the for loop, it works fine. But when it goes outside the for loop the variable vanishes into thin air. Console prints 'undefined' outside for loop.
Because Books.count is an API call and all the API call are async so In
for(var user in users){
// It Will call the Books.count and leave the callback Function without waiting for callback response.
Books.count({author: users[user]['id']}).exec(function(err, count){
users[user]['booksCount']=count;
});
}
//As callback result didn't came here but the controll came here
// So, users[user] will be undefined here
return res.view('sellers', {data: users});
Use promises:
async.forEachOf(users, function (value, user, callback) {
Books.count({author: users[user]['id']}).exec(function(err, count){
users[user]['booksCount']=count;
callback(err);
// callback function execute after getting the API result only
});
}, function (err) {
if (err) return res.serverError(err.message); // Or Error view
// You will find the data into the users[user]
return res.view('sellers', {data: users});
});

res.send() is running before nested function completes with value

The 'GetUsers' function is running and it returns the correct values as expected. However, res.send(users) is running before the nested function has completed with the value so it is undefined. I have tried doing the res.send(users) from inside the nested function but it doesn't recognize the function. I have also tried using return users but can't get it to work. Any help would be appreciated!
app.get('/GetUsers', function (req, res){
var url = 'mongodb://localhost:27017/users';
var users = "";
MongoClient.connect(url, function (err, db) {
if (err) {
console.log('Unable to connect to the mongoDB server. Error:', err);
} else {
console.log('Connection established to', url);
// Get the documents collection
var collection = db.collection('users');
// Get some users
collection.find().toArray(function (err, res) {
if (err) {
console.log(err);
} else {
console.log('Got Information from db.');
}
//Close connection
db.close();
console.log('db closed.');
users = res;
console.log(users);
});
}
});
res.send(users);
});
Just move res.send(users) inside your callback before/after you call console.log(users).
You reused the variable res in the toArray call, so please rename it there: ...toArray(function (err, res)... to ...toArray(function (err, result)... and also in users = res; to users = result;.
this is async call it will send the response and will not wait for the database connection function.
write res.send in call back function
write your res.send function where you are closing your data base connection.
here is detail How do I return the response from an asynchronous call?
Found the answer!!!
I needed to use res.send(users) in my callback after I had closed the database as pointed out by the users suggestions above. HOWEVER, that alone wasn't working as res.send(users) was erroring as it wasn't recognized as a function. I had to use res.send({'matched':users}) and then access my response objects on the client side like this: response.matched.objects etc.
Thanks for your help everyone!

NodeJS Cannot read property 'length' of undefined. [duplicate]

When I run collection.find() in MongoDB/Node/Express, I'd like to get a callback when it's finished. What's the correct syntax for this?
function (id,callback) {
var o_id = new BSON.ObjectID(id);
db.open(function(err,db){
db.collection('users',function(err,collection){
collection.find({'_id':o_id},function(err,results){ //What's the correct callback synatax here?
db.close();
callback(results);
}) //find
}) //collection
}); //open
}
That's the correct callback syntax, but what find provides to the callback is a Cursor, not an array of documents. So if you want your callback to provide results as an array of documents, call toArray on the cursor to return them:
collection.find({'_id':o_id}, function(err, cursor){
cursor.toArray(callback);
db.close();
});
Note that your function's callback still needs to provide an err parameter so that the caller knows whether the query worked or not.
2.x Driver Update
find now returns the cursor rather than providing it via a callback, so the typical usage can be simplified to:
collection.find({'_id': o_id}).toArray(function(err, results) {...});
Or in this case where a single document is expected, it's simpler to use findOne:
collection.findOne({'_id': o_id}, function(err, result) {...});
Based on JohnnyHK answer I simply wrapped my calls inside db.open() method and it worked. Thanks #JohnnyHK.
app.get('/answers', function (req, res){
db.open(function(err,db){ // <------everything wrapped inside this function
db.collection('answer', function(err, collection) {
collection.find().toArray(function(err, items) {
console.log(items);
res.send(items);
});
});
});
});
Hope it is helpful as an example.

mongodb native how to work with query

I'm trying to retrieve data from my mongolab DB using Node-mongodb-native
var findAll = function () {
var ddocs;
collection.find({}).each(function (arr, docs) {
ddocs = docs;
});
console.log(ddocs);
};
But it seems that when I log ddocs, it will give me undefined, but if I log docs it will show me the data.
Please help
How should I use this function ?
Thanks
Tzelon Machluf
You're basically trying to create a function that will return all of the documents in a collection? If so, the below should do work. However, I agree with #hgoebl and that you should work on your understanding of node as this is not likely the best way to accomplish what you're trying to do.
var ddocs;
var findAll = collection.find().toArray( function(err, docs) {
if(err)
throw err;
console.log('Collection returned');
return ddocs = docs;
});
setTimeout( function(err) {
if(err) throw err;
console.log(ddocs);
db.close();
}, 1000);
One thing in particular to note: collection.find is asynchronous, so the problem in your code (why it says ddocs is undefined) is that you're logging ddocs before the collection.find ever finished; thus, it's initialized, but no assigned any values. The Node convention is to nest callbacks so that everything happens in the right order and when it's ready.

Resources