Gregory Worrall
Gregory Worrall

Reputation: 181

Mongoose query fed into array

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

Answers (2)

Trung
Trung

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

Abdullah Rasheed
Abdullah Rasheed

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.

Another Issue

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.

Refactor with Two Options

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

Related Questions