Запрос мангуста внутри цикла forEach не может возвращать или устанавливать значение для переменной sum

#javascript #node.js #mongodb #mongoose

Вопрос:

Я пытаюсь рассчитать сумму каждой цены товара, запрошенной из базы данных, используя findById. Где идентификатор взят из массива объектов, которые я повторяю с помощью цикла forEach.

 module.exports.checkoutOrder = (reqBody, buyerId, isAdmin)=>{

    let sum =0;
    reqBody.items.forEach(item=>{

         Product.findById(item.productId,(error, result)=>{

            //console.log(result.price);
            sum  = result.price;

        })
    }) console.log(sum);
 

Проблема в том, что я, похоже, не могу получить или установить какую-либо переменную внутри блока findById. Даже если я помещу возврат в переменную sum, результат всегда будет один и тот же 0. Я уверен, что мой запрос возвращает данные, когда я выполняю консоль.результат регистрации.цена.

Я знаю, что есть другие способы суммирования данных, я просто хочу сначала узнать, почему это не работает таким образом?

Комментарии:

1. @NiceBooks, как я могу вывести сумму, хотя? Я просто вывел его из цикла

2. Пожалуйста, обратитесь к моему ответу.

Ответ №1:

2-й аргумент findById (err,result)=>{} -это обратный вызов, который по своей природе выполняется не сразу. console.log(sum) выполняется перед всеми обратными вызовами и, следовательно, выводит 0.

Вам нужно подождать, пока не будут выполнены все обратные вызовы. Грубым решением было бы обернуть console.log(sum) внутреннюю часть a setTimeout с разумной задержкой.

Лучшим решением было бы использовать exec метод создания объектов обещания Promise.all , чтобы дождаться завершения всех обещаний.

 let promiseList = await reqBody.items.map(async (item,i)=> 
  Product.findById(item.productId).exec() 
);

Promise.all(promiseList).then((productList)=> {
  let sum = productList.reduce((acc,product)=> acc   product.price, 0);
  console.log(sum);
}); 

Комментарии:

1. Привет. Я предположил, что этот код уже правильно отформатирован, и попробовал его, но получил ошибку «ожидание допустимо только в асинхронной функции».

2. Я все еще получаю ту же ошибку «ожидание допустимо только в асинхронной функции». Я полностью удалил forEach и заменил его вашим кодом. Ошибка указывает на ожидание перед телом запроса

3. Я проверил код с фиктивными номерами вместо запросов мангуста, и это работает. Вы добавили ключевое слово async перед обратным вызовом карты и вызовом метода exec() после findById ?

4. Лучше добавить новый код к вашему исходному вопросу в качестве правки, чтобы другие могли его увидеть. Я думаю, что вам нужно добавить асинхронность перед (reqBody, buyerId, isAdmin)=>, так как вы используете await внутри.

5. Вау. Теперь это сработало после того, как я поставил асинхронность перед (reqBody, buyerId, isAdmin)=>. Какое облегчение. Я собираюсь тщательно изучить ваш код. Я не хочу кодировать вслепую. Спасибо

Ответ №2:

Вы можете попытаться получить все документы с идентификаторами из массива:

 const arrOfIds = reqBody.items.map(item => item.id)
Product.find({ '_id': { $in: arrOfIds }}).toArray(function(err, data)...
 

Затем вы можете рассчитать сумму.

Комментарии:

1. Вы имеете в виду, что я могу сделать это без цикла forEach?

2. Да , вы можете подготовить массив только с идентификаторами от reqBody.items , а затем получить продукты с этими идентификаторами

3. не могли бы вы помочь мне отформатировать ваш код, извините, он кажется мне новым. Я получаю продукт с ошибкой.поиск-это не функция

4. Хорошо, теперь я могу утешить. логарифмические аррофиды. О конечном коде для команды «Кому». Функция массива, как вывести результирующие данные?

5. Здравствуйте, я надеюсь, что вы все еще можете прочитать это. Могу я спросить, что означает «$in» в этом коде?