Search code examples
javascripttypescriptlistlodash

Group array by nested object property and merge


I have an array with following structure:

BasketDish

[
  {
    id: string;
    quantity: number;
    Dish: AsyncItem<Dish | undefined>;
    basketID: string;
    createdAt?: string | null;
    updatedAt?: string | null;
    basketDishDishId?: string | null;
  }
]

Dish

[
  {
    id: string;
    name: string;
    price: number;
  },
  {
    id: string;
    name: string;
    price: number;
  }
]

I need to group the array by Dish.id and then create an array which accumulates the quantity and total price

From:

[
  {
    id: 1,
    name: BBQ Burger,
    price: 17
  },
  {
    id: 2,
    name: CheeseBurger,
    price: 15
  },
  {
    id: 2,
    name: CheeseBurger,
    price: 15
  },
]

To expected result:

[
  {
    id: 1,
    name: BBQ Burger,
    price: 17,
    total: 17,
    quantity: 1
  },
  {
    id: 2,
    name: CheeseBurger,
    price: 15,
    total: 30,
    quantity: 2
  },
]

I tried a lot with groupBy and merge, but couldn't figure it out

UPDATE

Thanks @BioStunt

Just needed to update your solution instead of group by id i had to group by Dish.id

/**
 * Merge Dishes with same id
 */
const groupedItems = chain(basketDishes)
  /** group items by key "id" */
  .groupBy(a => a.Dish?.id)
  /** convert grouped items */
  .map((items, id) => ({
    id: id,
    dishId: items[0]?.Dish?.id,
    name: items[0].Dish?.name,
    quantity: items.length,
    total: items.reduce((acc, item) => acc + item.Dish?.price!, 0),
  }))
  /** get result of chain */
  .value();

Solution

  • If I correctly understood your question, you should use chain + groupBy from lodash. In your case you have base item array:

    const basketDish = [ 
      { id: 1, name: 'BBQ Burger', price: 17 }, 
      { id: 2, name: 'CheeseBurger', price: 15 }, 
      { id: 2, name: 'CheeseBurger', price: 15 }, 
    ];
    

    To merge this data use this:

    const groupedItems = chain(basketDish)
      /** group items by key "id" */
      .groupBy('id')
      /** convert grouped items */
      .map((items, id) => ({
        id: Number(id),
        name: items[0].name,
        quantity: items.length,
        total: items.reduce((acc, item) => acc + item.price, 0)
      }))
      /** get result of chain */
      .value();
    

    Below is the console output:

    groupedItems.forEach((item) => 
      console.log(`${item.quantity} * ${item.name} | ${item.total}`)
    );