title: Wrapping MongoDB calls within a Promise
body: <p>I'm using Meteor (1.0.3) in general, but for one particular case I'm using a raw server side route to render a file -- so I'm outside a Meteor method.</p>
  
  <p>I'm using node fs.writeFile/fs.readFile and exec commands to call out to Linux command-line utilities too.</p>
  
  <p>My only point in brining this up is that the node calls are async of course.  And so I'm opted to use the node Q library in order to manage async callbacks.</p>
  
  <p>This all worked until I added a line to call out to the MongoDB database.</p>
  
  <p>A call like so:</p>
  
  <pre><code>var record_name = Mongo_Collection_Name.findOne({_personId: userId}, {fields: {'_id': 0}});
  </code></pre>
  
  <p>Produces the following error:</p>
  
  <blockquote>
    <p>[Error: Can't wait without a fiber]</p>
  </blockquote>
  
  <p><em>The error only occurs when I wrap the function in a Promise.</em></p>
  
  <p>For example, something like this will throw:</p>
  
  <pre><code>getRecordExample = function () {
    var deferred = Q.defer();
    var record_name = Mongo_Collection_Name.findOne({_personId: userId}, {fields: {'_id': 0}});
  
    // do something
  
    // if no error
    deferred.resolve(record_name);
  
    return deferred.promise;
  }
  </code></pre>
  
  <p>If I use the Meteor Fibers library I don't get the error:</p>
  
  <pre><code>getRecordExample = function () {
    var deferred = Q.defer();
    Fiber = Npm.require('fibers');
    var record_name
  
    Fiber(function () {
      record_name = Mongo_Collection_Name.findOne({_personId: userId});
    }).run()
    // do something
  
    // if no error
    deferred.resolve(record_name);
  
    return deferred.promise;
  }
  </code></pre>
  
  <p>but, the record_name variable is undefined outside the fiber, so I don't have a way to pass the variable outside of the Fiber scope as far as I can tell.</p>
  
  <h2>A More Precise Example</h2>
  
  <p>This is a little long, so you have to scroll down to see it all.  I'm basically building a workflow here so there are processes and subprocesses.</p>
  
  <pre><code>// both/routes.js
  Router.route('/get-route', function(req, res) {
    // get the userId then start the workflow below
  
    // using Promises here because these were firing concurrently
    Q(userId)
    .then(process_1)
    .then(process_2)
    .done();
  }, { name: 'server-side-ir-route', where: 'server' }
  
  // server.js
  process_1 = function (userId) {
    sub_process_1(userId);
  
    sub_process_2(userId);
  
    return userId;
  }
  
  process_2 = function (userId) {
    sub_process_3(userId);
  
    sub_process_4(userId);
  
    return userId;
  }
  
  sub_process_1 = function (userId) {
    var result = get_record_1(userId);
  
    // do stuff with result
  
    // using Q library to call out to async fs.writeFile, return Promise
    fs_writeFile_promise(result)
    .catch(function (error) {
      console.log('error in sub_process_1_write', error);
    })
    .done(function () {
      console.log('done with sub_process_1');
    }
  
    return userId;
  }.future() // &lt;-- if no future() here, the exception is thrown.
  
  sub_process_2 = function (userId) {
    var result = get_record_2(userId);
  
    // do stuff with result
  
    // using Q library to call out to async fs.writeFile, return Promise
    fs_writeFile_promise(result)
    .catch(function (error) {
      console.log('error in sub_process_1_write', error);
    })
    .done(function () {
      console.log('done with sub_process_1');
    }
  
    return userId;
  }.future()
  
  // async because of I/O operation (I think)
  get_record_1 = function (userId) {
    var record_1 = Mongo_Collection_Name.findOne({'userId': userId});
    // do stuff
    return record_1;
  }
  get_record_2 = function (userId) {
    var record_2 = Mongo_Collection_Name.findOne({'userId': userId});
    // do stuff
    return record_2;
  }
  
  // async operation using Q library to return a Promise
  fs_writeFile_promise = function (obj) {
    var deferred = Q.defer();
    fs.writeFile(obj.file, obj.datas, function (err, result) {
      if (err) deferred.reject(err);
      else deferred.resolve('write data completed');
    });
    return deferred.promise;
  }
  </code></pre>
  
  <p>For now, lets assume that the process_2 function is exactly like process_1</p>
  
  <p>Also, we should assume I have console.log('step_start') and console.log('step_end') in each function.  This is what it would look like on the command line:</p>
  
  <ul>
  <li>start processes </li>
  <li>end processes </li>
  <li>start processes 1 </li>
  <li>end processes 1 </li>
  <li>start processes 2 </li>
  <li>start sub processes 1 </li>
  <li>getting record 1 </li>
  <li>start sub processes 2 </li>
  <li>getting record 2 </li>
  <li>returning record 1 </li>
  <li>end sub processes 1 </li>
  <li>called writeData in sub process 1 </li>
  <li>returning record 2 </li>
  <li>called writeData in sub process 2 </li>
  <li>end processes 2 </li>
  <li>ending sub processes 1 </li>
  </ul>
  
  <p>The reason I had to place a Fiber (future) on the sub_process_1() function was because when I placed the function process_1() in the Q chain at the top I got the Error: Can't wait without a fiber].</p>
  
  <p>If I remove the process_1() in the Q chain at the top and remove the .future() from sub_process_1() no exception is thrown.</p>
  
  <h2>Questions</h2>
  
  <ul>
  <li>Why does calling out to a Mongo collection within a Promise cause a
  fiber error within a Meteor application?</li>
  <li>Does calling a async function within a sync function in general cause the sync function to become a async function?</li>
  <li>How do I solve this problem?</li>
  </ul>