En mi aplicación tengo una colección de categorías que guarda el título de la categoría con su ID de imagen. La imagen se guarda en otra colección con sus metadatos como ruta, tipo, etc. Entonces, para recuperar la categoría, debo recuperar la imagen de la categoría en la colección de imágenes por su ID y agregar la ruta de la imagen al objeto de categoría que se recupera de la colección de categorías y enviarla al cliente... Pero no sé a dónde debo enviar las categorías al cliente. Cuando envío la respuesta me encuentro con este error:
throw er; // Unhandled 'error' event ^ Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client at ServerResponse.setHeader (_http_outgoing.js:561:11) at ServerResponse.header (H:\node.js\online-store\app\node_modules\express\lib\response.js:771:10) at ServerResponse.send (H:\node.js\online-store\app\node_modules\express\lib\response.js:170:12) at ServerResponse.json (H:\node.js\online-store\app\node_modules\express\lib\response.js:267:15) at ServerResponse.send (H:\node.js\online-store\app\node_modules\express\lib\response.js:158:21) at H:\node.js\online-store\app\controllers\pcategory.controller.js:123:19 at H:\node.js\online-store\app\node_modules\mongoose\lib\model.js:4845:18 at processTicksAndRejections (internal/process/task_queues.js:77:11) Emitted 'error' event on Function instance at: at H:\node.js\online-store\app\node_modules\mongoose\lib\model.js:4847:15 at processTicksAndRejections (internal/process/task_queues.js:77:11) { code: 'ERR_HTTP_HEADERS_SENT' }Este es mi código:
exports.getAll = async (req, res) => { try{ const categories = await ProductCategory.find({}); categories.map(async(category)=>{ await File.findById(category.imageID).exec(function(err,file){ if(err){ console.log(err) }else if(file) { category.imagePath = file.file_path; tempCategories.push(category) } res.send(tempCategories); }) }) return res.send(tempCategories); }catch { res.json(err =>{ console.log(err); res.status(500).send({ message: err.message || "There is an error in retrieving category" }); }) } }El problema es que nada en su código está esperando a que se completen las operaciones asincrónicas que está realizando en la devolución de llamada del map , por lo que hace res.send al final de inmediato, y luego res.send nuevamente dentro de la devolución de llamada del map más tarde. cuando se completan las operaciones asincrónicas. En su lugar, espera a que terminen y envía el resultado.
Además, está usando res.send donde sospecho que quiere res.json , y luego está usando res.json incorrectamente (no requiere una devolución de llamada).
Ver comentarios:
exports.getAll = async (req, res) => { try { // Get the categories const categories = await ProductCategory.find({}); // Get the files for the categories, wait for the result const result = await Promise.all(categories.map(async (category) => { const file = await File.findById(category.imageID).exec(); // You probably can't modify the `category` object, so let's create // and return a new object return {...category, imagePath: file.file_path}; })); // Send the result converted to JSON return res.json(tempCategories); } catch (err) { // Accept the error // Send an error response res.status(500).json({ message: err.message || "There is an error in retrieving category" }); } }; Nota al margen: su código original estaba usando el map sin usar la matriz que crea. Eso es un antipatrón (lamentablemente, parece ser uno que alguien en algún lugar está enseñando). Escribí por qué y qué hacer aquí . (En mi actualización de su código, todavía uso map , pero uso la matriz que crea, pasándola a Promise.all para que podamos esperar a que se cumplan todas esas promesas).
Tu código Así,
Ahora el problema es que estás enviando encabezados dos veces.
Puede usar así, en primer lugar, declarar la matriz e insertar en ella lo que necesita y luego, al final de su lógica, devolverla o enviarla.
exports.getAll = async (req, res) => { try { const categories = await ProductCategory.find({}); let tempCategories = []; // New Line await Promise.all(categories.map(async (category) => { await File.findById(category.imageID).exec(function (err, file) { if (err) { console.log(err) } else if (file) { category.imagePath = file.file_path; tempCategories.push(category) } }); return category; })); res.send(tempCategories); } catch { res.json(err => { console.log(err); res.status(500).send({ message: err.message || "There is an error in retrieving category" }); }) } }