Tengo una matriz de objetos. cada objeto tiene una fecha. Quiero crear una nueva matriz de objetos, agrupando por semanas. Aquí hay un ejemplo de código:
const data = [ { "id": 1, "status": 1, "createdAt": "2022-05-01T08:28:36.284Z" }, { "id": 2, "status": 2, "createdAt": "2022-05-02T07:17:11.724Z" }, { "id": 3, "status": 3, "createdAt": "2022-05-10T07:03:44.465Z" }, { "id": 4, "status": 3, "createdAt": "2022-05-11T16:17:48.863Z" } ]El resultado que quiero es una matriz que divide el objeto por semanas como:
const newData = [ { "week": 1, "status": 1, "status": 2 }, { "week": 2, "status": 3, "status": 3 }]¿Es posible? ¿Puedo tener la misma propiedad 2 veces en el mismo objeto? gracias
Debe importar y usar moment.js para encontrar el número de la semana, para propósitos de gráficos, sugeriría algo como esto:
const data = [ { "id": 1, "status": 1, "createdAt": "2022-05-01T08:28:36.284Z" }, { "id": 2, "status": 2, "createdAt": "2022-05-02T07:17:11.724Z" }, { "id": 3, "status": 3, "createdAt": "2022-05-10T07:03:44.465Z" }, { "id": 4, "status": 3, "createdAt": "2022-05-11T16:17:48.863Z" } ] console.log(data.map(a => { return { status : a.status, week: moment(a.createdAt).week() } } )) <script src="https://cdn.jsdelivr.net/momentjs/2.13.0/moment.min.js"></script>Esto devolverá una matriz como esta:
[{ status: 1, week: 19 }, { status: 2, week: 19 }, { status: 3, week: 20 }, { status: 3, week: 20 }]En ECMAScript, un objeto no puede tener múltiples propiedades con el mismo nombre. Sin embargo, una opción es tener una matriz de objetos como:
[{week: weekNo, statuses: [status0, status1, status2, …]}] Los números de semana se repiten cada año, por lo que debe incluir el año, tal vez usando un formato ISO 8601 como 2022W03 que es fácil de analizar y ordenar léxicamente. Eso también se ocupará de las fechas que van más allá de un nuevo año.
Array.prototype.reduce con una función para calcular el número de semana puede hacer el trabajo:
// Return ISO week number: week starts on Monday, // first week of year is the one containing 4 Jan or // first Thursday of the year function getWeekNumber(d) { let z = n => (n<10? '0' : '') + n; d = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate())); d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay()||7)); var yearStart = new Date(Date.UTC(d.getUTCFullYear(),0,1)); var weekNo = Math.ceil(( ( (d - yearStart) / 86400000) + 1)/7); return `${d.getUTCFullYear()}W${z(weekNo)}`; } function groupByWeek(data) { // Pointer to location of week in array let index = {}; let newData = data.reduce((acc, obj) => { let weekNo = getWeekNumber(new Date(obj.createdAt)); if (!index[weekNo]) { index[weekNo] = acc.length; acc.push({week: weekNo, statuses: []}); } acc[index[weekNo]].statuses.push(obj.status); return acc; }, []); // Sort by week number newData.sort((a, b) => a.week.localeCompare(b.week)); return newData; } let data = [ {"id": 1, "status": 1, "createdAt": "2022-05-01T08:28:36.284Z"}, {"id": 2, "status": 2, "createdAt": "2022-05-02T07:17:11.724Z"}, {"id": 3, "status": 3, "createdAt": "2022-05-10T07:03:44.465Z"}, {"id": 4, "status": 3, "createdAt": "2022-05-11T16:17:48.863Z"}, {"id": 5, "status": 1, "createdAt": "2023-01-05T08:28:36.284Z"}, ]; console.log(groupByWeek(data))Como no podemos tener varias propiedades con el mismo nombre en un objeto, debe almacenar el estado en una matriz.
let getWeekNbr = date => { date = formateDate(date); let firstDay = new Date(date.getFullYear(),0,1); let nbrDays = Math.floor((date - firstDay) / (24*60*60*1000)); return Math.ceil((date.getDay() + 1 + nbrDays) / 7); } let formateDate = date => new Date(Date.parse(date)); let groupBy = (arr, key) => arr.reduce((rv, x) => { (rv[x[key]] = rv[x[key]] || []).push(x); return rv; }, {}); let formatedData = data.map(d => ({...d, week: getWeekNbr(d.createdAt)})); // calcule week nbr let groupedData = groupBy(formatedData, 'week'); // group data by week propertie's value let result = Object.values(groupedData).map(arr => ({week: arr.at(0).week, status: arr.map(d => d.status)})); // formating result console.log(result); // Output // [ // { "week": 18, "status": [1, 2] }, // { "week": 19, "status": [3] }, // { "week": 20, "status": [3] } // ]