1

I'm new to JS in general, but I am trying to query some data from MongoDB. Basically, my first query retrieves information for the session with the specified session id. The second query does a simple geospacial query for documents with a location near the specified location.

I'm using the mongodb-native javascript driver. All of these query methods return their results in callbacks, so they're non-blocking. This is the root of my troubles. What I'm needing to do is retrieve the results of the second query, and create an Array of sessionIds of all the returned documents. Then I'm going to pass those to a function later. But, I can't generate this array and use it anywhere outside the callback.

Does anyone have any idea how to properly do this?

db.collection('sessions', function(err, collection) {
  collection.findOne({'sessionId': client.sessionId}, function(err, result) {
    collection.find({'geolocation': {$near: [result.geolocation.latitude, result.geolocation.longitude]}}, function(err, cursor) {
      cursor.toArray(function(err, item) {

      console.log(item);
    });
  });
});

2 Answers 2

6

Functions are the only thing on javascript that "enclose" scope.

This means that the variable items in your inner callback function are not accessible on the outer scope.

You can define a variable in the outer scope so it will be visible to all the inner ones:

function getItems(callback) {
  var items;

  function doSomething() {
    console.log(items);
    callback(items);
  }

  db.collection('sessions', function(err, collection) {
    collection.findOne({'sessionId': client.sessionId}, function(err, result) {
      collection.find({'geolocation': {$near: [result.geolocation.latitude, result.geolocation.longitude]}}, function(err, cursor) {
        cursor.toArray(function(err, docs) {
          items = docs;
          doSomething();
         });
       });
     });
   });
}
0

Node.js is asynchronous, so your code should be written to match it.

I've found this model useful. Each nested callback jumble is wrapped in helper function that calls the argument callback 'next' with error code and result.

function getSessionIds( sessionId, next ) {
    db.collection('sessions', function(err, collection) {
      if (err) return next(err);
      collection.findOne({sessionId: sessionId}, function(err, doc) {
          if (err) return next(err);
          if (!doc) return next(false);
          collection.find({geolocation: {$near: [doc.geolocation.latitude, result.geolocation.longitude]}}.toArray(function(err, items) {
              return next(err, items);
          });
      });
    });
}

Then in your calling code

getSessionIds( someid, _has_items);
function _has_items(err, items) {
   if( err ) // failed, do something
   console.log(items);
}

Not the answer you're looking for? Browse other questions tagged or ask your own question.