Асинхронный поиск mongodb в цикле завершается раньше, чем возвращаются все данные

Я использую служебный модуль Async для возврата элементов из базы данных Mongodb. Я хочу сделать это асинхронно. У меня возникают проблемы при попытке вернуть эти предметы.

Я хочу запустить обратный вызов, как только ВСЕ User.find()'s будут завершены, прямо сейчас async.each() завершается раньше и дает мне только один элемент из базы данных, когда он должен возвращать их все.

Код ниже:

async.each(lessons, function(lesson, next) { // For each item in lesson array
    if (_.isEmpty(lesson.lesson_grades) == true) { // Check if the grades array is empty
        return;
    } else {
        async.each(lesson.lesson_grades, function(grade, next) { // For each grade in grade array
            User.find({ // Find user from grade user_id
                _id: grade.user_id,
            }, '-salt -hashedPassword', function(err, user) {

                grade["name"] = user[0].name; // Add name
                grade["email"] = user[0].email; // Add email

                next(); // !! I think this is where the problem lies, it fires next() once the first item has been returned - so it doesn't get to the other items !!
            });
        }, function(err) {
            next(lessons);
        });
    }
}, function(lessons, err) {
    return res.json(200, lessons); // Return modified lessons (with name and email) to browser, currently only returns one but returns them all if a setTimeout() is added, making it a premature callback problem
});

Может ли кто-нибудь указать мне в правильном направлении, как это сделать правильно? Должен ли я отслеживать итерации? Любая помощь будет оценена по достоинству.


person Tiffany Lowe    schedule 08.11.2014    source источник


Ответы (1)


Соглашение, которому следует async, заключается в том, что функция обратного вызова принимает два аргумента: ошибку и результат, в таком порядке. Различие между ошибкой и результатом важно, потому что async немедленно завершает работу, если получает ошибку. Часть, которая говорит function(err) { next(lessons); }, неверна - async неверно интерпретирует lessons как ошибку, потому что это правда. Следует читать:

function(err, result) {
    next(err, result);
}

Или на самом деле вы могли бы просто заменить функцию на next.

Кроме того, ближе к концу function(lessons, error) должно быть function(error).

Еще одна вещь, на которую следует обратить внимание: вы должны убедиться, что каждый обратный вызов вызывается один раз и только один раз. Но если он запускает блок if вместо блока else, next никогда не вызывается; async никогда не закончится. Он не заблокирует запуск другого кода, но никогда не достигнет return res.json(200, lessons);. (Это также может привести к утечке памяти, я не уверен.)

И последнее: возврат результата внутри обратного вызова ничего не даст. Похоже, вы пытаетесь вызвать весь этот асинхронный код из синхронной функции; это не работает. res.json будет вызываться, но если он возвращает значение, возможно, вы хотели использовать это значение в качестве аргумента для другой функции обратного вызова из другого места. Но мне нужно больше информации о том, что вы пытаетесь сделать.

person David Knipe    schedule 08.11.2014
comment
спасибо, что нашли время ответить. Я внес изменения, которые вы предложили, но у меня все еще та же проблема. Не подскажете, как переписать? Я пытался весь день с тех пор, как вы опубликовали этот ответ. Спасибо. - person Tiffany Lowe; 09.11.2014
comment
Как вы получаете результат от этого? Кроме того, обратите внимание на мое изменение в моем ответе - функция в конце вообще не должна иметь lessons в качестве аргумента (вместо этого она должна быть переменной закрытия). - person David Knipe; 09.11.2014