I have an array that holds multiple objects and each object has a date, amount and id as keys.
I'd like to group all the objects by month and then return the sum of the amount keys for each month.
Here's my first approach but I'm pretty sure it's not the right way to go.
I'm manually defining the Start and the End of each month.
Is there another way to do this more dynamically ?
1 - Get the start and end of each month
2 - Group the array by month without using lodash ( I'm open to use moment.js )
3 - Sum the values of each month
3 - Return the name of the month the total
The Array structure in json
"expenses": [
{
"amount": 5.97,
"date": "09/01/2022",
"id": 1
},
]
The Logic in React
const MonthsTotal = ({ expenses }) => {
let novemberTotal = 0;
let decemberTotal = 0;
expenses
.filter((items) => {
return items.date >= "11/01/2022" && items.date <= "11/31/2022";
})
.forEach((item) => {
novemberTotal = item.amount;
});
expenses
.filter((items) => {
return items.date >= "12/01/2022" && items.date <= "12/31/2022";
})
.forEach((item) => {
decemberTotal = item.amount;
});
The output in react
This is how I'm outputting the data
return (
<Box>
<Card variant="outlined">
<div> November </div>
<div>{novemberTotal}</div>
</Card>
</Box>
<Box>
<Card variant="outlined">
<div>December</div>
<div>{decemberTotal}</div>
</Card>
</Box>
)
export default MonthsTotal;
CodePudding user response:
Here is an alternative approach using JavaScript's built-in Date object and the Array.reduce() method:
Parse the dates in the expenses array into Date objects using Date.parse() or a library like moment.js. Use the Array.reduce() method to group the expenses by month. For each expense, extract the month and year from the Date object and use that as the key for the group. Add the amount of the expense to the total for that group. Return an object with the month and year as the key and the total as the value. Example below:
const groupExpensesByMonth = (expenses) => {
return expenses.reduce((acc, expense) => {
// Extract the month and year from the date
const date = new Date(expense.date);
const month = date.getMonth();
const year = date.getFullYear();
const key = `${month}-${year}`;
// Initialize the total for the month if it doesn't exist
if (!acc[key]) {
acc[key] = 0;
}
// Add the amount to the total for the month
acc[key] = expense.amount;
return acc;
}, {});
}
const expenses = [
{
"amount": 5.97,
"date": "09/01/2022",
"id": 1
},
{
"amount": 10.50,
"date": "09/15/2022",
"id": 2
},
{
"amount": 20.00,
"date": "10/01/2022",
"id": 3
},
{
"amount": 30.00,
"date": "11/01/2022",
"id": 4
},
];
const groupedExpenses = groupExpensesByMonth(expenses);
console.log(groupedExpenses);
// Output:
// {
// "8-2022": 5.97,
// "9-2022": 10.50,
// "10-2022": 20.00,
// "11-2022": 30.00
// }
To display the totals in your React component, you can iterate over the keys in the object and display the month and year as the label and the total as the value. You can use the Date object's getMonth() method to get the name of the month based on the month number.
const MonthsTotal = ({ expenses }) => {
const groupedExpenses = groupExpensesByMonth(expenses);
return (
<div>
{Object.keys(groupedExpenses).map((key) => {
const [month, year] = key.split('-');
const monthName = new Date(0).toLocaleString('en-US', { month: 'long' });
return (
<Box>
<Card variant="outlined">
<div>{`${monthName} ${year}`}</div>
<div>{groupedExpenses[key]}</div
</Card>
</Box>
);
})}
</div>
);
}
export default MonthsTotal;
This should display a list of cards, with each card showing the month and year as the label and the total for that month as the value.
CodePudding user response:
i think reduce() is what are you looking for.
const arr = [
{ date: '2022-01-01', amount: 100, id: 1 },
{ date: '2022-01-03', amount: 200, id: 2 },
{ date: '2022-02-01', amount: 300, id: 3 },
{ date: '2022-02-02', amount: 400, id: 4 },
{ date: '2022-03-01', amount: 500, id: 5 }
];
const groupedByMonth = arr.reduce((acc, obj) => {
// Get the month and year from the date string
const month = obj.date.slice(0, 7);
//only the month
//const month = obj.date.split('/')[0];
if (acc[month]) {
acc[month] = obj.amount;
} else {
acc[month] = obj.amount;
}
return acc;
}, {});
console.log(groupedByMonth);
/*
{
'2022-01': 300,
'2022-02': 700,
'2022-03': 500
}
*/
//only the month output
/*
{
'01': 300,
'02': 700,
'03': 500
}
*/