简体   繁体   中英

Fill array with results from Mongodb find()

In my Mongodb database I have a collection of documents of this type (Mongoose description):

{ colour: String, addedDate: {type: Date} }

for example, here is a sample of the data:

{colour: 'white', addedDate: '2014-09-24T23:00:00.000Z'}
{colour: 'red', addedDate: '2014-09-24T23:00:00.000Z'}
{colour: 'white', addedDate: '2013-11-24T23:00:00.000Z'}
{colour: 'red', addedDate: '2012-09-24T23:00:00.000Z'}
{colour: 'white', addedDate: '2014-01-24T23:00:00.000Z'}
{colour: 'yellow', addedDate: '2014-09-24T23:00:00.000Z'},

I would like to get for certain colours (specified in an array), the documents with the latest 'addedDate' and store the result in an array.

Here is my code:

var Colour   = require('../app/models/colour');
var colours = ['white', 'red'];
var results = [];

for (var i = 0; i<colours.length; i++) {
    var name = colours[i];
    (function(output, colour_name) {
        Colour.find({name: colour_name})
            .sort('-addedDate').limit(1).exec(
                function (err, obj) {
                    if (err) return console.log(err);
                    output.push(obj);
                    console.log('output LOG:' + output);
                }
            );
    })(results, name);
}
// Now use the results array
console.log('OUTPUT:' results);

In the 'output LOG:' I get the array output as it should be (I am not showing here the _id for simplicity):

output LOG: {colour: 'white', addedDate: '2014-09-24T23:00:00.000Z'} 
output LOG: {colour: 'white', addedDate: '2014-09-24T23:00:00.000Z'}, {colour: 'red', addedDate: '2014-09-24T23:00:00.000Z'}

However, the final output is still empty.

OUTPUT:

How can I fill the 'results' array? In fact, I would like to pass it to a webpage, so I would like to collect all the results for those colours in advance before rendering the page.

Probably the function passed to exec is run asynchronously as its db operation, in that case results array won't be filled at the time you are logging it.

try:

setTimeout(function()
    console.log('OUTPUT:' results);
}, 1000);

to check if thats the case, assuming the db transaction takes max 1000ms.

NB: This is a guess as I have never worked with node/mongo.

In this section,

(function(output, colour_name) {

    /* Fetch documents here and send to client from here */

})(results, name);

The variables 'results','name' are passed to the function and due to scope problem those values will not be updated outside(even if they are changed inside).

You can fetch the documents and sent those documents to clients just after fetching it.

Mongoose calls are asynchronous. What's happening is that you're adding each Color.find call to the event queue and then you're calling console.log('OUTPUT:', results); before any Color.find call has run. This means that at that point in time, your array is empty.

Solution

Pass in the number of remaining calls and a callback. After every colour has been queried, you call your callback. Here's a fiddle

var colours = ['white', 'red'];
var result = {
   items: [],
   left: colours.length
};

function myCallback(param){
    console.log(param);
}

for(var i=0; i<colours.length; ++i){
    (function(results, colour_name, cb){
      ...
      setTimeout(function(){ // remove this, just simulating an async call
        // this should be inside the Color.find callback
        result.items.push(colour_name);
        result.left--;
        if (!result.left) {
          cb(result.items);
        }
      },0);
      ...
    }(result, colours[i], myCallback ));
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM