Mongoose и promises: как получить массив результатов запроса?

Использование mongoose для запроса результатов из db и Q для promises, но мне трудно оборачивать голову, просто получая список доступных пользователей. В настоящее время у меня есть что-то вроде этого:

var checkForPerson = function( person ) {
    people = mongoose.model('Person', Person)

    return people.findOne({"_id": person }, function(err, doc) {
        if (err) console.log(err)

        if (doc !== null) {
            return doc
        } else { 
            console.log('no results')
        }

    })
}

var promises = someArrayOfIds.map(checkForPerson);

// this is where I would like to have an array of models
var users = Q.all(promises)

//this fires off before the people.findOne query above to users is undefined
SomeOtherFunction( users )

Как мне решить, заканчивать ли запросы до SomeOtherFunction, не выполняя тонны неаккуратных обратных вызовов?

Ответ 1

Другое предложение - использовать MongoDB $in для передачи массива в find и эффективно получать большой набор результатов. Каждый из них будет объектом Mongoose.

var promise = people.find({ _id: { $in: someArrayOfIds }).exec();
promise.then(function(arrayOfPeople) {
  // array of people ... do what you want here...
});

Это будет намного эффективнее, чем создание нескольких запросов, по одному для каждого _id.

Ответ 2

Ответ на вопрос "как я могу продолжить с promises" почти всегда с .then. Это обетованная аналогия ; и завершает асинхронное утверждение. Вы можете вернуть promises в него, и он будет распаковывать их перед продолжением.

Q.all(promises).then(function(users){
    SomeOtherFunction(users);
});

Или просто Q.all(promise).then(SomeOtherFunction)

Вам также понадобится findOne, чтобы на самом деле вернуть promises. Вы можете либо использовать Q.nfcall, который вызывает функцию node, либо обещает его самостоятельно.

То, что Q.all делает, принимает массив из promises и выполняет, когда все они делают и отклоняют, когда один из них отклоняется. Возможно, вы захотите добавить обработчик .catch в случае отказа любого из запросов или использования .done, чтобы обозначить конец цепочки. Другие библиотеки обещаний, такие как Bluebird, будут забирать ошибки для вас даже без .done или добавления явного обработчика, к сожалению Q не делает этого.

Ответ 3

Вы также можете использовать q (npm install q)

var q = require('q')
, aPromise = mongooseModelA.find({_id: aId}).exec()
, bPromise = mongooseModelB.find({_id: bId}).exec();

q.all([aPromise, bPromise]).then(function(bothA_and_B) {
  console.log(bothA_and_B);
});