0

I have a database select function where I want to have the following output format:

{
  "recipe_id" : 1,
  "recipe_name": "Spaghetti Bolognese",
  "created_at": "2021-01-01 08:23:19.120",
  "steps": [
    {
      "step_id": 11,
      "step_number": 1,
      "step_instructions": "Put a large saucepan on a medium heat",
      "ingredients": []
    },
    {
      "step_id": 12,
      "step_number": 2,
      "step_instructions": "Add 1 tbsp olive oil",
      "ingredients": [
        { "ingredient_id": 27, "ingredient_name": "olive oil", "quantity": 0.014 }
      ]
    },
  ]
}

I created the following database function to do the steps portion:

const getIngredientsStepById = async (step_id) =>{
  const data = await db('step_ingredient_info as sii')
    .join('steps', 'steps.step_id', 'sii.step_id')
    .join('ingredients', 'ingredients.ingredient_id', 'sii.ingredient_id')
    .where('steps.step_id', step_id)

  let returnObj = data[0]? data.map(ingredient => {
     return {
      ingredient_id: ingredient.ingredient_id,
      ingredient_name: ingredient.ingredient_name,
      quantity: ingredient.quantity
    }
  }) : []

  return returnObj
}

Which provides the following output

[
    {
        "ingredient_id": 1,
        "ingredient_name": "egg",
        "quantity": "2 eggs"
    },
    {
        "ingredient_id": 2,
        "ingredient_name": "salt",
        "quantity": "a pinch of salt"
    }
]

I'm trying to combine it with this current code:

const getRecipeById = async recipe_id => {

  let data = await db('recipes as r')
    .join('steps as st', 'st.recipe_id', 'r.recipe_id')
    .where('r.recipe_id', recipe_id)
    .orderBy('st.step_number')

  let recipeObj = {
    recipe_name: data[0].recipe_name,
    steps:
      data[0].step_id ? data.map(step =>{
        return {
          step_id: step.step_id,
          step_number: step.step_number,
          instructions: step.step_instructions
        }
      }) : []
  };

  return recipeObj
}

Which currently has this output, which is good:

{
    "recipe_name": "fried egg",
    "steps": [
        {
            "step_id": 1,
            "step_number": 1,
            "instructions": "add oil and heat pan"
        },
        {
            "step_id": 2,
            "step_number": 2,
            "instructions": "crack egg into pan in medium heat for 2-3 mins and sprinkle salt"
        },
        {
            "step_id": 3,
            "step_number": 3,
            "instructions": "serve"
        }
    ]
}

But the moment, I try to use async to grab the ingredients so I can add an ingredients array inside the steps, the code stops working in that, it shows up in the console but doesn't get an output.

The code with async is:

const getRecipeById = async recipe_id => {

  let data = await db('recipes as r')
    .join('steps as st', 'st.recipe_id', 'r.recipe_id')
    .where('r.recipe_id', recipe_id)
    .orderBy('st.step_number')

  let recipeObj = {
    recipe_name: data[0].recipe_name,
    steps:
      data[0].step_id ? data.map(async step =>{
        let ingredients = await getIngredientsStepById(step.step_id);
        console.log(ingredients);
        return {
          step_id: step.step_id,
          step_number: step.step_number,
          instructions: step.step_instructions,
          ingredients: ingredients
        }
      }) : []
  };

  return recipeObj
}

enter image description here

enter image description here

dp_chua
  • 123
  • 1
  • 2
  • 10
  • Does this answer your question? [Using async/await with a forEach loop](https://stackoverflow.com/questions/37576685/using-async-await-with-a-foreach-loop) – Klaycon May 13 '21 at 23:04
  • An `async` function returns a promise, so `map()` produces an array of promises. You'll need to call `Promise.all` on that and `await` the result. – Bergi May 13 '21 at 23:13

1 Answers1

0

map, forEach, reduce etc, async will have no effect.

But looking at your code you could change the second stage into a simple for of..

const getRecipeById = async recipe_id => {

  let data = await db('recipes as r')
    .join('steps as st', 'st.recipe_id', 'r.recipe_id')
    .where('r.recipe_id', recipe_id)
    .orderBy('st.step_number')

  let recipeObj = {
    recipe_name: data[0].recipe_name,
    steps:
      data[0].step_id ? data.map(step =>{
        return {
          step_id: step.step_id,
          step_number: step.step_number,
          instructions: step.step_instructions,
        }
      }) : []
  };

  for (const step of recipeObj.steps) {
     step.ingredients = await getIngredientsStepById(step.step_id);
  }

  return recipeObj
}
Keith
  • 22,005
  • 2
  • 27
  • 44
  • You still have an `async` function in your `map` call – Bergi May 13 '21 at 23:12
  • Removed the async on the map call as Bergi pointed out, but the rest was godsend. Thank you! Didn't even think of it going this route. – dp_chua May 13 '21 at 23:17