Necesito realizar alguna modificación en una API que devuelve algo como esto:
[ { "_id": "0000000000000000001", "name": "Random name", "categories": [ "5eb8548330550e017f8902e6", "5eb2548630550e117f8909eb", "5eb6548930550e017f8909e9" ] }, {...}, ]las categorías de cada resultado se devuelven como identificadores de sus respectivos documentos. Necesito manipular el resultado para que el campo de categorías de cada objeto tenga una matriz de objetos y cada objeto tenga la identificación y el nombre de su categoría. Hago un ejemplo de lo que debería ser el resultado:
[ { "_id": "0000000000000000001", "name": "Random name", "categories": [ {"_id": "5eb8548330550e017f8902e6", "name": "Category 1"}, {"_id": "5eb2548630550e117f8909eb", "name": "Category 2"}, {"_id": "5eb6548930550e017f8909e9", "name": "Category 3"}, ] }, {...}, ]Necesito hacer esto usando JS simple y hasta ahora esto es lo que he hecho, pero devuelve una matriz de indefinidos:
const resultArray = await Promise.all( searchResults.map(async (item) => { item.categories.map(async (categoryId) => { return await CategoryType.find({ _id: categoryId}); }); }) );Por el momento, estoy tratando de obtener cada documento de categoría para cada identificación en el campo de categorías. Apuesto a que la razón por la que obtengo una matriz de indefinidos es que estoy manejando la sincronización de manera incorrecta, pero no puedo entender cómo.
Para responder estrictamente a su pregunta: le falta sincronización (porque Array.prototype.map 'ignora' async):
const resultArray = await Promise.all( searchResults.map(async (item) => { const promises = item.categories.map(async (categoryId) => { // you dont want find, but findOne btw return await CategoryType.findOne({ _id: categoryId}); }); const categories = await Promise.all(promises) item.categories = categories return item }) );Esto se puede simplificar como
const resultArray = await Promise.all( searchResults.map(async item => { item.categories = await Promise.all(item.categories.map(categoryId => { return CategoryType.findOne({ _id: categoryId}) })) return item }) );Pero la forma correcta de hacerlo es probable que use poblar
const mongoose = require('mongoose') mongoose.connect('mongodb://localhost:27017/dummy') const Category = mongoose.model('Category', { name:String, }, 'categories'); const X = mongoose.model('X', { name:String, categories: [{type: mongoose.Types.ObjectId, ref: 'Category'}] }, 'xs'); ;(async()=>{ try { mongoose.set('debug', true) const xs = await X.find().populate('categories') console.log('xs : ', xs[0]) } finally { mongoose.disconnect() } })() Por cierto, notará que la mangosta, debajo del capó, usa find({ _id: {$in:[]}}) que hace solo una solicitud (así que es mejor) que hacer múltiples findOne (como lo hace usted)