2

I'm working with mongojs and I have to retrieve a field from an object taken from mongodb. I can not understand how to return the field:

  function retrieveVertById(id){

  var result = [];
  db.clusters.find({id: id}, function (err, clusters){
  if( err || !clusters) console.log("No cluster found");
  else clusters.forEach( function (cluster) {

    vert = cluster["vertices"];
    result.push(vert);
    console.log(result);


   });
 })
return result;
};

var a = retrieveVertById("001");
console.log(a);

The print inside the 'forEach' prints the correct value: (ex. [ [ [ 8, 2, 2 ], [ 2, 2, 5 ], [ 2, 2, 2 ], [ 5, 2, 2 ] ] ] ) On the contrary the print outside the cycle shows an empty array. what does not work with the return? Thanks in advance for your help.

Alberto De Caro
  • 5,147
  • 9
  • 47
  • 73
  • console.log(vert) is ok? – monkeyinsight Apr 27 '13 at 15:33
  • Yes, also console.log(vert) in the forEach prints the correct value. – Francesco Maglia Apr 27 '13 at 15:39
  • Could you explain your question a little better? By print do you mean the console.log? Which console.log is not showing the right value, `a` or `return result, did you make your own `id` or are you mistaken for `_id`? – Datsik Apr 27 '13 at 15:40
  • 1
    You can't return the result of an asynchronous operation like `find` from a function. You have to use callbacks as your `retrieveVertById` function returns before the `find` callback occurs. Do some searches of existing questions as this is a very common point of confusion. – JohnnyHK Apr 27 '13 at 15:44
  • For print I mean the instruction 'console.log'. The right value is shown only in the forEach. It seems that 'return' has no effect because the instruction 'console.log(a)' shows an empty array instead of the instruction 'console.log(result)' that shows the correct value. – Francesco Maglia Apr 27 '13 at 15:46

2 Answers2

1

I've not used mongojs, but any db lookup will almost certainly be asynchronous. This means the function you passed to db.clusters.find will not run immediately, but rather when the asynchronous call returns from mongo. Instead of returning a value from retrieveVertById, try a callback function instead:

function retrieveVertById(id, successCallback) {

  db.clusters.find({
    id: id
  }, function (err, clusters) {
    if (err || !clusters) {
        console.log("No cluster found");
    } else {
        var result = [];
        clusters.forEach(function (cluster) {
            vert = cluster["vertices"];
            result.push(vert);
        });
        successCallback(result);
    }
  });
};

retrieveVertById("001", function(result) {
  console.log(result);
});
ljfranklin
  • 480
  • 3
  • 12
  • I was able to take the field with the callback Thank you very much for your time! – Francesco Maglia Apr 27 '13 at 16:07
  • When I call `retrieveVertById` in the bottom of my example, I'm passing in the callback as an anonymous function. I gave `retrieveVertById` a second parameter called `successCallback`. So the line `successCallback(result);` actually calls the anonymous function: `function(result) { console.log(result); }` that I passed in as an argument. Understanding callback functions is a must when writing asynchronous programs. – ljfranklin Apr 27 '13 at 16:09
  • @FrancescoMaglia - Glad to help! Be sure mark an accepted answer to close out this question. – ljfranklin Apr 27 '13 at 16:16
  • Last question: How can I assign the returned value to a variable? I explain better: I want to do something like this: var vert = retriveVertById("001") – Francesco Maglia Apr 27 '13 at 16:29
  • @FrancescoMaglia - Short answer: move the code that references that variable into the body of the callback. So `function(result) { console.log(result); }` becomes `function(result) { var vert = result; //rest of your code }`. Long answer: do some research on JavaScript callback functions. There's certainly too much to cover in a comment box. – ljfranklin Apr 27 '13 at 16:40
0

oh, i see... you should remember that javascript is async language

return result;

after forEach() will not return result from inside forEach(). you should send result after last value parsed.

var i = 0;
clusters.forEach( function (cluster) {
    vert = cluster["vertices"];
    result.push(vert);
    if (i >= clusters.length)
        return result;
    i++;
});
monkeyinsight
  • 4,719
  • 1
  • 20
  • 28
  • Couple issues. Since there are several nested functions in this example, a `return` statement in the forEach body will not 'bubble-up' and act as a `return` for the `retrieveVertById` function. Second, if the `db.cluster.find` method is asynchronous as you said, then you can't return any values from it without the use of a callback function. – ljfranklin Apr 27 '13 at 16:01