Sé que esta pregunta ya se ha hecho, pero simplemente no puedo hacer esto bien. Intenté usar promesas pero fue en vano. Cuando la consola registra elementos de req.user sigue siendo una matriz vacía. Sé que debería usar promesas, pero tengo problemas para implementarlas. Ayuda apreciada
app.get('/cart',checkAuthenticated, async (req, res) => { if(req.user.cart.length > 0){ req.user.items = [] req.user.cart.map(async (item) => { var itemDescription = await productsModel.findOne({id: item.itemId}) req.user.items.push(itemDescription) }); console.log(req.user) }La razón por la que está vacío es porque no espera a que finalicen todas las funciones asíncronas en el mapa. Prueba esto:
await Promise.all(req.user.cart.map(async (item) => { var itemDescription = await productsModel.findOne({id: item.itemId}) req.user.items.push(itemDescription) }));Tenga en cuenta que @jfriend00 ha comentado que esta implementación no garantizará el orden de los elementos en req.user.items.
Debido a que ya está utilizando el mapa, es más sencillo hacer lo siguiente y también garantiza el orden de los elementos:
req.user.items = await Promise.all(req.user.cart.map(async (item) => { var itemDescription = await productsModel.findOne({id: item.itemId}) return itemDescription; }));.map() no tiene en cuenta las promesas. No presta atención a la promesa de que devuelve su función de devolución de llamada async . Entonces, tan pronto como presione await productsModel.findOne(...) , esa función async devuelve una promesa incumplida y .map() avanza a la siguiente iteración del ciclo.
Hay muchas maneras diferentes de resolver esto. Si desea utilizar .map() , debe prestar atención a la promesa de que su devolución de llamada se devolverá de esta manera:
app.get('/cart', checkAuthenticated, async (req, res) => { if (req.user.cart.length > 0) { req.user.items = await Promise.all(req.user.cart.map((item) => { return productsModel.findOne({ id: item.itemId }); })); console.log(req.user) } });La implementación anterior intentará ejecutar todas las búsquedas en la base de datos en paralelo.
Una implementación algo más simple solo usa un bucle for simple y ejecuta las búsquedas en la base de datos una a la vez:
app.get('/cart', checkAuthenticated, async (req, res) => { if (req.user.cart.length > 0) { req.user.items = []; for (let item of req.user.cart) { req.user.items.push(await productsModel.findOne({ id: item.itemId })); } console.log(req.user) } });En su ejemplo, la matriz aún está vacía porque la devolución de llamada en la función de mapa funciona de manera asíncrona, por lo tanto, debe esperar mientras se completa el código. Debido a que la función de mapa devuelve una matriz de promesas, todas deben resolverse utilizando Promise.all:
app.get('/cart', checkAuthenticated, async (req, res) => { if (req.user.cart.length > 0) { req.user.items = [] const promises = req.user.cart.map(async (item) => { var itemDescription = await productsModel.findOne({ id: item.itemId }) req.user.items.push(itemDescription) }); await Promise.all(promises); console.log(req.user) } });De lo contrario, puede reemplazar la función de mapa con bucle for:
app.get('/cart', checkAuthenticated, async (req, res) => { if (req.user.cart.length > 0) { req.user.items = [] for (const item of req.user.cart) { var itemDescription = await productsModel.findOne({ id: item.itemId }) req.user.items.push(itemDescription) } console.log(req.user) } });