0

I'm trying to learn how to use promises with arrays and some async mongo queries. Here's the method that I currently have, but Q.allSettled executes before my mongo queries b/c nothing has been pushed to the array yet that Q.allSettled is looking at.

How can I modify this method so that all my async queries are executed before Q.allSettled.spread executes?

function buildCaseObject() {

        var returnPromise = Q.defer();
        var promises = [];
        var allObjects = [];

        var subjects = rdb.collection('subjects');
        var observations = rdb.collection('observation');

        // Loop through all subjects from current subject list
        subjects.find({'player._id': {$elemMatch: {root: '1.2.3.99.100.2', extension: {$in : subjectList}}}}).each(function(err, subject) {

          var def = Q.defer();
          promises.push(def);

          if (err) {
            def.reject(err);
          } else if (subject== null) {
            return def.resolve();
          }

          var caseObject = {};
          caseObject.subject= clone(subject);

          // Add observations to the subject
          observations.find({subjectId: subject._id}).toArray(function(err, allObs) {

            if (err) {
              def.reject(err);
            }

            caseObject.observations = clone(allObs);
            allObjects.push(caseObject);
            def.resolve();
          });

        });

        Q.allSettled(promises).then(function() {
          // GETTING IN HERE BEFORE GETTING INTO THE CALLBACK OF subjects.find.
          // THEREFORE THE ARRAY IS EMPTY
          console.log('in spread');
          console.log(allObjects.length);
          returnPromise.resolve(allObjects);
        }).fail(function(err) {
          returnPromise.reject(err);
        });

        return returnPromise.promise;
      }
Catfish
  • 18,876
  • 54
  • 209
  • 353
  • You should promisify mongo, and then compose promises - find is async so allSettled runs on an empty array and returns immediately. – Benjamin Gruenbaum Sep 04 '14 at 20:34
  • That's more or less what I pointed out in my question. I'm not sure how to do it, hence the question :p – Catfish Sep 04 '14 at 20:39
  • http://stackoverflow.com/questions/22519784/how-do-i-convert-an-existing-callback-api-to-promises and also read http://stackoverflow.com/questions/23803743/what-is-the-deferred-antipattern-and-how-do-i-avoid-it – Benjamin Gruenbaum Sep 04 '14 at 20:41
  • Those 2 links are examples without arrays. I know how to do the simple things. I'm stuck on this particular question regarding arrays. Please re-read thoroughly. – Catfish Sep 04 '14 at 20:43
  • How is this any different? You'd promisify `.toArray` and then chain promises instead of use deferreds. – Benjamin Gruenbaum Sep 04 '14 at 20:44
  • Because it wouldn't even get that far. You'd have to promisify `subjects.find.each` first. I've tried that and my attempt failed. It still gets into Q.allSettled immediately. – Catfish Sep 04 '14 at 20:52
  • 2
    You can't promisify each - you need to use .toArray instead and promisify that. – Benjamin Gruenbaum Sep 05 '14 at 05:49
  • Thanks for the help @BenjaminGruenbaum. It made more sense after you pointed out to promisify toArray instead of .each. – Catfish Sep 09 '14 at 20:34

1 Answers1

1

Two things:

Q.allSettled will only capture the promises that are in the array at the time it is called. You will need to wait until you have populated the array, perhaps with a promise for the completion of the each call above.

The other is that Q.defer() returns a {promise, resolve} pair. You will need to add only the promise to the promises array.

promises.push(def.promise);
Kris Kowal
  • 3,866
  • 2
  • 24
  • 24
  • 1
    As stated by Benjamin in the comments, the problem is that there is no "completion" of the `each` call - its callback will be called multiple times asynchronously. – Bergi Sep 06 '14 at 12:10
  • Ok so I ended up getting this working actually with using `.each` but it's probably not as elegant of a solution as using .toArray rather than each. I basically had to create another promise to call before calling `Q.allSettled`. Also pushing the promise to the array and not the pair was a key piece too. – Catfish Sep 09 '14 at 20:34