Reputation: 181
I'm having a few problems with this chunk of code. So I'm using Mongoose to get data from my database, I then want to push a piece of that data into an array called 'authors' and then use that data seperately.
I can access the data, because if I've debugged it using console.log(), however I can't get that data outside the while loop. What's happening?
That last line responds with '[]'
while (i < 8) {
var search = User.find({'twitter.id' : collected[i].author});
search.exec(function (err, user){
if (err) return console.error(err);
var result = (user[0].twitter.username);
authors.push(result);
});
i = i + 1;
}
console.log(authors);
Upvotes: 1
Views: 657
Reputation: 1382
Because Javascript is asynchronous, the console.log(authors)
will be executed even if the loop still running.
To handle async in js, you can use this async module, it very powerful and easy to use.
--- EDIT
var _ = require('lodash');
var authors;
User.find({ "twitter.id" : {$in: _.map(collected, 'author')}}).exec()
.then(function(docs) {
author = docs;
// Do something
})
I think you can just do this, it basically the same with @inspired
Upvotes: 2
Reputation: 3752
That last line responds with '[]'
This is because User.find()
is an async
call. So when you step out of the loop when i = 8
, you will hit console.log(authors)
before the data has returned.
It seems that you are making 8
separate calls to the database when you only need to make 1
call. If you have an array called collected
that you are looping through. and it looks like this.
var collected = [
{ author : "23423423"},
{ author : "23423424"},
{ author : "23423425"},
{ author : "23423426"},
];
You can gather all of the twitter ids using the .map function.
var twitterIds = collected.map(function(a){return a.author});
Now twitterIds == ["23423423", "23423424", "23423425", "23423426"]
.
You can then use $in operator to select the documents where the value of twitter.id
equals any value in the specified array.
You can then do this User.find({ "twitter.id" : {$in : twitterIds}});
It will return a document containing all of the matching documents which you then can manipulate. Now you have reduced to 1
call instead of 8
.
I would refactor the code in either of the two ways:
1) Return the Query
function search(twitterIds){
var query = User.find({ "twitter.id" : twitterIds});
return query;
}
Then you can use it as so:
var searchQuery = search(twitterIds);
searchQuery.exec(function(err,users){
if(err) return console.log(err);
//do something with users..
users.forEach(function(user){
console.log(user.twitter.username);// do something here
});
}
2) Return the Promise
function search(twitterIds){
var promise = User.find({ "twitter.id" : twitterIds}).exec();
return promise;
}
Then you can use it as so:
var promise = search(twitterIds);
promise.then(function(users){
//do something...
}).error(function(err){
console.log(errr);
});
Before using the async, library I would start here to see if this would get the job done.
Upvotes: 2