Tri Nguyen
Tri Nguyen

Reputation: 1808

Mongoose - How to save results to an array

I have a mongodb query and I want to save the results to an array. I also define an empty array outside of query.

       var dietaryResults = [];

       for (var key in dietary){
            Restaurant.find(
                { $text : { $search : dietary[key] } },
                { score : { $meta: "textScore" } }
            ).sort({ score : { $meta : 'textScore' } }).exec(function(err, results) {
                for (var i in results){
                    dietaryResults.push(results[i]);
                }
                console.log(dietaryResults);
            });
        }

If I do console.log(dietaryResults) inside the query like above, I can see the results being pushed into the array. But if I put console.log(dietaryResults) outside of the array (which what I want), it prints an empty string. Can anyone explain this behavior and suggest a solution for this? Thanks.

Upvotes: 1

Views: 4424

Answers (4)

Tri Nguyen
Tri Nguyen

Reputation: 1808

When I use bluebird (which is a kind of Promise) it works.

 var Promise = require('bluebird');
 var mongoose = Promise.promisifyAll(require('mongoose'));

 var promises = Restaurant.find({ $text : { $search : query } }, function(err, results) {
     results.forEach(function(element) {
         finalResults.push(element);
     });
 });

 Promise.all(promises).then(function() {
     console.log(finalResults);
 }).error(console.error);

Upvotes: 2

Eyal Cohen
Eyal Cohen

Reputation: 1288

As of javascript asynchronicity fashion, You can't be sure that the .exec callback will run (and end) before the for loop end. (you can have a better understanding on this topic by reading about the event-loop)

This way, dietaryResults can be empty (depend on the query speed) in any other place.

You can read more about using promises with mongoose and node in order to be sure dietaryResults will be full with the results, and also have better understanding on this topic by reading about Node event loop.

For now, I'm not fully sure this will work - but that's is your direction:

var query = {...} // (enter your query here) 
var dietaryResults = [];

Object.entries(diatery).map(async key => {
  const results = await Restaurant.find(query).sort();
  results.map(result => dietaryResults.push(result));
});

console.log(dietaryResults);

Upvotes: 0

Michael Kapustey
Michael Kapustey

Reputation: 173

Restaurant.find is asynchronous.

Function insinde .exec part is being executed after loop ends.

Try

 for (var key in dietary){
        Restaurant.find(
            { $text : { $search : dietary[key] } },
            { score : { $meta: "textScore" } }
        ).sort({ score : { $meta : 'textScore' } }).exec(function(err, results) {
            for (var i in results){
                dietaryResults.push(results[i]);
            }
            console.log('added');
        });
    }
 console.log('loop end');

You will be able to see, that 'loop end' log will be printed before 'added' log. If you need all results in array, you should fill this array in callback. There is no way to get data synchronously.

For more information about callbacks and async functions check out this article: https://www.tutorialspoint.com/nodejs/nodejs_callbacks_concept.htm

I'd suggest to search for all required data at once and avoid searching inside loop to have single callback and do everything you need with results inside that callback.

Smth like this may work. If not you should search for some way to get all data in one request

 Restaurant.find(
    { $text : { $search : { $in: Object.values(dietary)} } },
    { score : { $meta: "textScore" } }
 ).sort({ score : { $meta : 'textScore' } }).exec(function(err, results) {
    for (var i in results){
        dietaryResults.push(results[i]);
    }
        //do stuff here;
    });

Upvotes: 1

ŞükSefHam
ŞükSefHam

Reputation: 167

You need callback or promise.You can use outside of this **Restaurant.find( ** this:setTimeOut(function s(){console.log(dietaryResults)},1000)

Because you need to learn async functions.

Upvotes: 0

Related Questions