1

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);

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

6 Comments

Very interesting! So how can I wait until I have the data to then pass that data around?
@gregjw I'll update my answer, but why are you placing find in the loop?
I think I have a bit of an odd use-case. So that I have to handle 8 seperate requests. So I have 8 images and for each image, I want to find its user and then I'll pass both pieces of data to my view. So I'm not sure if I can modify your solution for that problem?
ok. did you try the first case yet? did it work? and then what criteria are you using to find the image?
It did. If all the images have one author, it'll return one user. If there are two authors, two users. But I need to differentiate which user is attached to each image.
|
2

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

1 Comment

Could you give me an example on how I could use the async module in this situation?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.