Home > Enterprise >  How can I parse an array of objects that are related to conditionally reduce it down?
How can I parse an array of objects that are related to conditionally reduce it down?

Time:03-17

I have an array

[
  {
    "id": 19,
    "name": "rice",
    "food_group": null,
    "created_at": "2022-03-15T02:38:17.911Z",
    "updated_at": "2022-03-15T02:38:17.911Z"
  },
  {
    "id": 20,
    "name": "water",
    "food_group": null,
    "created_at": "2022-03-15T02:38:17.942Z",
    "updated_at": "2022-03-15T02:38:17.942Z"
  },
  {
    "id": 8,
    "recipe_id": 19,
    "ingredient_id": 19,
    "quantity": 1,
    "measurement_unit": "cup",
    "created_at": "2022-03-15T02:38:17.932Z",
    "updated_at": "2022-03-15T02:38:17.932Z"
  },
  {
    "id": 9,
    "recipe_id": 19,
    "ingredient_id": 20,
    "quantity": 23,
    "measurement_unit": "cup",
    "created_at": "2022-03-15T02:38:17.945Z",
    "updated_at": "2022-03-15T02:38:17.945Z"
  }
]

And I want to reduce these objects down to two objects that represent the ingredient and measurements, making it displayable. Since the ingredient_id is available in the measurement/quantity object I believe this is doable, but I am struggling to see how to do this.

I have a sandbox here where I've been trying

So ideally the array would become

[{"rice": { "measurement_unit": cup, quantity: 1}}...]

CodePudding user response:

While this amount of data manipulation is definitely something better done on the back-end, it is totally do-able in the front-end with JavaScript.

I would manually split the array into the two types, and then create a new array of all the ingredients, but fill in the matching measurement details for each.

// separate the ingredients from the measurements
const ingredientsArr = data.filter(x => x.name);
const measurementsArr = data.filter(x => x.measurement_unit);

// map the ingredients to a new array of objects
const output = ingredientsArr.map(({ id, name }) => {

  // find matching measurement by ingredient id
  const matchingMeasurement = measurementsArr.find(x => x.ingredient_id === id);

  // return object that we want
  return {
    [name]: {
      measurement_unit: matchingMeasurement.measurement_unit,
      quantity: matchingMeasurement.quantity
    }
  }
});

CodePudding user response:

What you're doing has flaw in case there are multiple recipes with same ingredients in the list, so probably it's better to do the other way around, anyway following is what you asked:

var objs = [{
    "id": 19,
    "name": "rice",
    "food_group": null,
    "created_at": "2022-03-15T02:38:17.911Z",
    "updated_at": "2022-03-15T02:38:17.911Z"
  },
  {
    "id": 20,
    "name": "water",
    "food_group": null,
    "created_at": "2022-03-15T02:38:17.942Z",
    "updated_at": "2022-03-15T02:38:17.942Z"
  },
  {
    "id": 8,
    "recipe_id": 19,
    "ingredient_id": 19,
    "quantity": 1,
    "measurement_unit": "cup",
    "created_at": "2022-03-15T02:38:17.932Z",
    "updated_at": "2022-03-15T02:38:17.932Z"
  },
  {
    "id": 9,
    "recipe_id": 19,
    "ingredient_id": 20,
    "quantity": 23,
    "measurement_unit": "cup",
    "created_at": "2022-03-15T02:38:17.945Z",
    "updated_at": "2022-03-15T02:38:17.945Z"
  }
]

var ingredients = []
var recipes = []

objs.forEach(obj => {
  if ('name' in obj) {
    ingredients.push(obj)
  } else {
    recipes.push(obj)
  }
})

ingredients = ingredients.map(ingredient => {

  match = recipes.find(recipe =>
    recipe.ingredient_id === ingredient.id
  )

  return {
    [ingredient.name]: {
      measurement_unit: match.measurement_unit,
      quantity: match.quantity
    }
  }
})

console.log(ingredients)

  • Related