Kammryn Dancy Kammryn Dancy - 3 months ago 69
Javascript Question

cursor.toArray() returns a promise instead of array

Currently using node 4.3.2 and mongo 2.6. I am attempting to get a whole collection (three documents currently in the collection). When i use this bit of code i run into an issue.

function checkUpdateTime(last_updated){
var collection = db.collection(last_updated);
collection.insert({a:1});
updateTimes = collection.find({a:1}).toArray();
}
var updateTimes = [];
checkUpdateTime('last_updated');
console.log(updateTimes);


When this code is tun updateTimes is a promise and not the array i was hoping for. The goal is the edit the array then insert it back into the collection later.The insert statement works but the retrieval of the documents simply doesn't operate the way i was expecting. I have tried quite a few versions of this code but no dice.

I guess it boils down to me wondering why a promise is being returned?

Answer

The MongoDB driver offers two options for handling asynchronous operations:

  • through callbacks that get passed by the caller
  • by returning a promise to the caller

When you don't pass a callback, like in your case, it will return a promise.

So you need to make a choice here. One choice that you can't choose is "make this code run synchronously", though.

I prefer promises:

function checkUpdateTime(last_updated){
  var collection = db.collection(last_updated);
  return collection.insert({ a : 1 }) // also async
                   .then(function() {
                     return collection.find({ a : 1 }).toArray();
                   });
}
checkUpdateTime('last_updated').then(function(updateTimes) {
  console.log(updateTimes);
});

You could always go a bit more fancy and use something like Promise.coroutine, that will make your code look a bit more synchronous (even though it isn't):

const Promise     = require('bluebird');
const MongoClient = require('mongodb').MongoClient;

let checkUpdateTime = Promise.coroutine(function* (db, last_updated){
  let collection = db.collection(last_updated);
  yield collection.insert({ a : 1 });
  return yield collection.find({ a : 1 }).toArray();
});

Promise.coroutine(function *() {
  let db = yield MongoClient.connect('mongodb://localhost/test');
  let updateTimes = yield checkUpdateTime(db, 'foobar');
  console.log(updateTimes);
})();

Or async/await, using Babel:

const MongoClient = require('mongodb').MongoClient;

async function checkUpdateTime(db, last_updated) {
  let collection = db.collection(last_updated);
  await collection.insert({ a : 1 });
  return await collection.find({ a : 1 }).toArray();
}

(async function() {
  let db = await MongoClient.connect('mongodb://localhost/test');
  let updateTimes = await checkUpdateTime(db, 'foobar');
  console.log(updateTimes);
})();