Estoy tratando de recorrer una serie de objetos, guardarlos en MongoDB y luego agregar los ObjectId devueltos a un esquema principal que luego también se guarda. Estoy perdido aquí.
Todo se guarda correctamente, pero aparentemente la Recipe (principal) se guarda antes de que obtenga los ObjectId devueltos de las Tag (hijos) . Siento que he usado las palabras clave async y en await con demasiada frecuencia.
¿Alguien puede ayudar? Código simplificado, pero puedo publicar más si es necesario.
Esquema principal:
const recipe = new mongoose.Schema( { name: String, ingredients: [ { type: mongoose.SchemaTypes.ObjectId, ref: "Ingredient", }, ], } );Esquema hijo:
const ingredientSchema = new mongoose.Schema({ value: String, label: String, });Carga útil:
{ name: "Rezept", ingredients: [ { label: "zutat", value: "Zutat", }, { label: "schokolade", value: "Schokolade", }, ], };Mi enrutador:
recipesRouter.post("/", async (req, res) => { const { body } = req; const saveIngredients = async () => { let ingredientIDs = []; body.ingredients.map(async (ingredient) => { const i = new Ingredient({ value: ingredient.value, label: ingredient.label, }); const savedIngredient = await i.save(); ingredientIDs.push(savedIngredient._id); }); return ingredientIDs; }; const recipe = new Recipe({ name: body.name, ingredients: (await saveIngredients()) || [], }); const savedRecipe = await recipe.save(); res.status(201).json(savedRecipe); });Receta devuelta:
savedRecipe: { name: 'asd', ingredients: [], _id: new ObjectId("62782b45a431e6efb7b8b1a7"), } Como dije, ambos ingredientes individualmente y la receta se guardan en MongoDB después de esto, pero no las identificaciones de los ingredientes en la receta. La receta devuelta tiene una matriz vacía en ingredients . Supongo que la receta se guarda demasiado pronto antes de que MongoDB pueda devolver ObjectIds para los ingredientes.
Gracias por cualquier ayuda.
En primer lugar, su método de publicación es asíncrono, por lo que todo lo que contiene se envuelve en una promesa resuelta automáticamente.
¿Realmente necesita hacer que sus saveIngredients asíncronos? En mi humilde opinión, es mejor dejar que saveIngredients no esté en otro asíncrono.
Y luego podemos eliminar la lista vacía, y solo esperar a que saveIngredients() termine primero.
const recipe = new Recipe({ name: body.name, ingredients: await saveIngredients(), }); Su suposición es correcta, la receta se guardó primero porque se cumplieron todas las condiciones porque no es necesario esperar a que se guarden los ingredientes ya que proporcionó un [] como valor predeterminado. Y su saveIngredients se ejecuta en paralelo.
Lo tengo smh. Resulta que async en un .map o .foreach no funciona bien. Lo convertí en un for loop simple. ¡Todavía está hinchado/muchos pasos en mi opinión, pero funciona!
recipesRouter.post("/", async (req, res) => { const { body } = req; const saveIngredients = async () => { let ingredientIDs = []; for (let i = 0; i < body.ingredients.length; i++) { const el = body.ingredients[i]; const ing = new Ingredient({ value: el.value, label: el.label, }); const savedIngredient = await ing.save(); ingredientIDs.push(savedIngredient._id); } return ingredientIDs; }; const ingredientIDs = await saveIngredients(); const recipe = new Recipe({ name: body.name, ingredients: ingredientIDs, }); const savedRecipe = await recipe.save(); res.status(201).json(savedRecipe); });