'Javascript JSON transform using Map, Reduce, Aggregate
I am beating my head trying to figure out this transformation.
This is the format of the JSON
I have:
{
"itineraryId": "063fc878-b118-49fc-9106-39d51f647c9e",
"reservations": [
{
"confirmNumber": "54047SC008976",
"startDate": "2021-11-20T00:00:00.000Z"
},
{
"confirmNumber": "54047SC008975",
"startDate": "2021-11-13T00:00:00.000Z"
},
{
"confirmNumber": "54058SC007379",
"startDate": "2021-08-13T00:00:00.000Z"
}
]
}
I need:
[{
"itineraryId": "063fc878-b118-49fc-9106-39d51f647c9e",
"month": "November 2021",
"reservations": [{
"confirmNumber": "54047SC008976",
"startDate": "2021-11-20T00:00:00.000Z"
},
{
"confirmNumber": "54047SC008975",
"startDate": "2021-11-13T00:00:00.000Z"
}
]
}, {
"itineraryId": "063fc878-b118-49fc-9106-39d51f647c9e",
"month": "August 2021",
"reservations": [{
"confirmNumber": "54058SC007379",
"startDate": "2021-08-13T00:00:00.000Z"
}]
}]
I need it that way so that I can build a SectionList in my react native app. I tried so many different options (aggregate+map+reduce) but I m not able to get it to this format. Any guides I can follow to help me?
The problem is a lot more complicated but I have simplified it by removing all the unneeded data properties. I was able to figure out the structure I need by looking at the example in the SectionList page and figuring out the structure of that 
Edit: Pasting the picture of what it looks like when I follow one of the solutions. Nov 2022 shows up before Nov 2021

Solution 1:[1]
I've often wished for some kind of easy "group by" function in JavaScript, but you can achieve the same effect with reduce(). Essentially, you can build up an array of grouped results by either creating or updating a group depending on if it already exists during each call to the reducer function:
const monthNames = ["January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
];
const initial = {
"itineraryId": "063fc878-b118-49fc-9106-39d51f647c9e",
"reservations": [{
"confirmNumber": "54047SC008976",
"startDate": "2021-11-20T00:00:00.000Z"
},
{
"confirmNumber": "54047SC008975",
"startDate": "2021-11-13T00:00:00.000Z"
},
{
"confirmNumber": "54058SC007379",
"startDate": "2021-08-13T00:00:00.000Z"
},
{
"confirmNumber": "54047SC008971",
"startDate": "2020-11-13T00:00:00.000Z"
},
{
"confirmNumber": "54047SC008973",
"startDate": "2022-11-13T00:00:00.000Z"
}
]
};
const groupedReservations = initial.reservations
.sort((reservationA, reservationB) => {
// Sort descending according to startDate
return new Date(reservationB.startDate) - new Date(reservationA.startDate);
})
.reduce((reservationGroups, reservation) =>
{
// Calculate the key that uniquely identifies the group, then look it up
const date = new Date(reservation.startDate);
const reservationMonth = monthNames[date.getMonth()] + " " + date.getFullYear();
const existingGroup = reservationGroups.find(group => group.month === reservationMonth);
// If the group doesn't exist, create it - otherwise, add the reservation to it
if (!existingGroup) {
reservationGroups.push({
itineraryId: initial.itineraryId,
month: reservationMonth,
reservations: [reservation]
});
} else {
existingGroup.reservations.push(reservation);
}
return reservationGroups;
}, []);
console.log(groupedReservations);
Note that I basically treat itineraryId as an afterthought here, since denormalizing the data didn't seem like an important step. Let me know if the context of your code requires something different.
Solution 2:[2]
Here minified implementation
// Convert ISO date to human readable date : August 2021
const formatYearMonth = (dateISO) => {
const formatYearMonth = (dateISO) => {
const monthNames = ["January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
];
const parsedDate = new Date(dateISO)
const year = parsedDate.getFullYear()
const month = monthNames[parsedDate.getMonth()]
return `${month} ${year}`;
};
return `${month} ${year}`;
};
const getItineraryMonths = (reservations) => {
let months = {};
reservations.forEach((reservation) => {
const formattedMonth = formatYearMonth(reservation.startDate);
months[formattedMonth] = formattedMonth;
});
return Object.keys(months);
};
// Get reservation in specified month for specific itinerary
const getReservationsInMonth = (reservations, formatedMonthIn) => {
return reservations.filter((reservation) => {
const formattedMonth = formatYearMonth(reservation.startDate);
return formattedMonth === formatedMonthIn;
});
};
// Reformat JSON response
const formatJsonResponse = (response) => {
const itineraryMonths = getItineraryMonths(response.reservations);
const formattedResult = itineraryMonths.map((month) => {
return {
itineraryId: response.itineraryId,
month,
reservations: getReservationsInMonth(response.reservations, month),
};
});
return formattedResult;
};
console.log(formatJsonResponse(input));
Test solution - https://replit.com/@EmmanuelBYIRING/json-sanitise#index.js
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 |
