1

I have a simple array that I want to group it's objects by date so I used this function

  const groupedDates= Object.entries(
    items.reduce((acc, { product, price, type, date }) => {
      if (!acc[date]) {
        acc[date] = [];
      }
      acc[date].push({ product, price, type date });
      return acc;
    }, {})
  ).map(([date, items]) => ({ date, items }));

the array

  const items = [
    {
      id: 1,
      product: "milk",
      price: 10,
      type: "drink"
      date: "01/01/2022",
    },
    {
      id: 2,
      product: "coca",
      price: 11,
      type: "drink"
      date: "01/01/2022",
    },
    {
      id: 3,
      product: "pepsi",
      price: 20,
      type: "drink"
      date: "01/01/2024",
    },
    {
      id: 4,
      product: "carrots",
      price: 30,
      type: "food",
      date: "01/01/2023",
    },
  ];

I got this result

{

0: [
 date: 01/01/2022,
 items : [
     0 : {
      id: 1,
      product: "milk",
      price: 10,
      type: "drink"
      date: "01/01/2022"
     }
     1 : {
      id: 2,
      product: "coca",
      price: 11,
      type: "drink"
      date: "01/01/2022",
     }
], 

1: [
 date: "01/01/2024",
 items : [
     0 : {
      id: 3,
      product: "pepsi",
      price: 20,
      type: "drink"
      date: "01/01/2024",
     }
],

2: [
  date: "01/01/2023",
  items: [
      0:{
      id: 4,
      product: "carrots",
      price: 30,
      type: "food",
      date: "01/01/2023"
   }
    ]
  ]
}

Issue:
I cannot seem to figure out how to access items1 when it exists.

What I have tried
is the map below but it only returns the first level of items which is 0 and if I do items1 it returns an error because not all arrays have a second item.

{groupedDates.map((obj) => (
     {obj.items[0].product}))}

UPDATE I'd also like to get the total for each date so I can have a card that has the Date + The total + each item and it's individual price. After getting some help from @Nick, I've managed to output the date, the item and it's price, now I'm still missing the total price for the date.

enter image description here

enter image description here

5
  • Is there a specific reason to have numeric keys? Would not it be more efficient if you have the key to be the date itself? Commented Sep 28, 2022 at 9:08
  • "01/01/2024":[{ id: 4, product: "carrots", price: 30, type: "food", date: "01/01/2023" },] Commented Sep 28, 2022 at 9:10
  • yeah that could work too but it's not really the issue is it ? Commented Sep 28, 2022 at 9:17
  • 1
    something like {groupedDates.map((obj) => obj.items.map(i => i.product))} perhaps? Commented Sep 28, 2022 at 12:04
  • This works for me and does exactly what I want so yeah you can post your answer :) Commented Sep 28, 2022 at 13:01

1 Answer 1

1

You need to iterate the items in each obj to get the list of products:

const items = [
  { id: 1, product: "milk", price: 10, type: "drink", date: "01/01/2022" },
  { id: 2, product: "coca", price: 11, type: "drink", date: "01/01/2022" },
  { id: 3, product: "pepsi", price: 20, type: "drink", date: "01/01/2024" },
  { id: 4, product: "carrots", price: 30, type: "food", date: "01/01/2023" },
];

const groupedDates = Object.entries(
  items.reduce((acc, { product, price, type, date }) => {
    if (!acc[date]) {
      acc[date] = [];
    }
    acc[date].push({ product, price, type, date });
    return acc;
  }, {})
).map(([date, items]) => ({ date, items }));

const allProducts = groupedDates.map((obj) => obj.items.map(i => i.product))

console.log(allProducts)

const totalsByDate = groupedDates.map(({ date, items }) => (
  { [date] : items.reduce((acc, item) => acc + item.price, 0) }
))

console.log(totalsByDate)
.as-console-wrapper { max-height:100% !important; top 0 }

Note I would make groupedDates an object with its keys being the dates; that will make looking up data for a given date much easier. For example:

const items = [
  { id: 1, product: "milk", price: 10, type: "drink", date: "01/01/2022" },
  { id: 2, product: "coca", price: 11, type: "drink", date: "01/01/2022" },
  { id: 3, product: "pepsi", price: 20, type: "drink", date: "01/01/2024" },
  { id: 4, product: "carrots", price: 30, type: "food", date: "01/01/2023" },
];

const groupedDates = items.reduce((acc, { date, ...rest }) => {
    acc[date] = (acc[date] || []).concat({ ...rest })
    return acc;
  }, {})

console.log(groupedDates)

const allProducts = Object.values(groupedDates)
  .flatMap(arr => arr.map(obj => obj.product))

console.log(allProducts)

const totalsByDate = Object.entries(groupedDates).map(([ date, items ]) => (
  { [date] : items.reduce((acc, item) => acc + item.price, 0) }
))

console.log(totalsByDate)
.as-console-wrapper { max-height:100% !important; top 0; }

Sign up to request clarification or add additional context in comments.

8 Comments

there might me a small mistake here, in flatMap(arr ... ) it says arr is not defined
any idea on how to get the total for the prices of each date ? ``` const getTotalByDate= groupedDates.forEach(function (i) { const sum = i.items.reduce(function (sum, elem) { return sum + elem.amount; }, 0); console.log(sum); }); ``` This kind of does the job and it returns the total for each date but I cannot figure out how to output that
@DavidNy sorry about the arr issue, that was a typo which strangely still works in my browser. I've fixed that. I've also added a function to total values by date to each snippet. Let me know if that helps
no worries. I prefer working with the first reduce function, converting groupedDates to an object makes it a bit confusing. '' totalsByDate '' that you suggested above works with the second method where groupedDates is converted to an object. It's just a bit confusing when you want to output that in a div. {groupedDates.map((obj) => obj.items.map(i => i.product))} not quiet sure how I can output the total of each date within the map function. Maybe it'd be more simple to add a totalAmount in each array, so each array would be something like: date, items, total
@DavidNy I saw your other question, if you updated it with some sample HTML that you are trying to add the totals to, it would make it easier to answer
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.