I have difficulties finding a way to map an array of objects, to a new array that will need to have objects defined by specific fields and values plus I also need to add objects by a single day, will explain details further down and I cannot use for loops of any kind due code style restriction I have in my project
The data I need to map to a new array
[ { id: 'C12-TBX4', studyId: 'TBX4', siteId: 'USA-1', statusType: 'INCOMPLETE', statusFrom: '2020-12-01', statusTo: '2020-12-05' }, { id: 'C13-TBX4', studyId: 'TBX4', siteId: 'USA-1', statusType: 'INCOMPLETE', statusFrom: '2020-12-03', statusTo: '2020-12-07' }, { id: 'C14-TBX4', studyId: 'TBX4', siteId: 'USA-1', statusType: 'INCOMPLETE', statusFrom: '2020-12-05', statusTo: '2020-12-08' }, { id: 'C15-TBX4', studyId: 'TBX4', siteId: null, statusType: 'REJECTED', statusFrom: '2020-12-05', statusTo: '2020-12-08' }, { id: 'C16-TBX4', studyId: 'TBX4', siteId: null, statusType: 'REJECTED', statusFrom: '2020-12-05', statusTo: '2020-12-09' }, { id: 'C17-TBX4', studyId: 'TBX4', siteId: 'USA-1', statusType: 'DROPOUT', eligible: true, statusFrom: '2020-12-05', statusTo: '2020-12-09' }, { id: 'C17-TBX4', studyId: 'TBX4', siteId: 'USA-1', statusType: 'DROPOUT', eligible: false, statusFrom: '2020-12-05', statusTo: '2020-12-10' } ]
The above array needs to be compared and re-mapped using the following dates
[ 2020-12-01T00:00:00.000Z, 2020-12-02T00:00:00.000Z, 2020-12-03T00:00:00.000Z, 2020-12-04T00:00:00.000Z, 2020-12-05T00:00:00.000Z, 2020-12-06T00:00:00.000Z, 2020-12-07T00:00:00.000Z, 2020-12-08T00:00:00.000Z, 2020-12-09T00:00:00.000Z ]
The dates are in a range from the minimum to the maximum date of the data object.
The data object contains an interval as statusFrom
and statusTo
; I need to have a new array of objects where we will have a single day from the dates object.
The array also will include a new field called total
which is the total of id
in a single study with the same statusType
on the same day.
To give an example of the result I need to have
[ // INCOMPLETE { "studyId": "TBX4", "siteId": "USA-1", "day": "2020-12-01", "statusType": "INCOMPLETE", "total": 1 // Only "id": "C12-TBX4", }, { "studyId": "TBX4", "siteId": "USA-1", "day": "2020-12-02", "statusType": "INCOMPLETE", "total": 1 // Only "id": "C12-TBX4", }, { "studyId": "TBX4", "siteId": "USA-1", "day": "2020-12-03", "statusType": "INCOMPLETE", "total": 2 // we have C13-TBX4 + C12-TBX4, dates are overlapping }, { "studyId": "TBX4", "siteId": "USA-1", "day": "2020-12-03", "statusType": "INCOMPLETE", "total": 2 // we have C13-TBX4 + C12-TBX4, dates are overlapping }, { "studyId": "TBX4", "siteId": "USA-1", "day": "2020-12-04", "statusType": "INCOMPLETE", "total": 2 // we have C13-TBX4 + C12-TBX4, dates are overlapping }, { "studyId": "TBX4", "siteId": "USA-1", "day": "2020-12-05", // we include only status from and exclude status to "statusType": "INCOMPLETE", "total": 2 // we have C13-TBX4 + C14-TBX4, dates are overlapping -- C12-TBX4 is excluded }, { "studyId": "TBX4", "siteId": "USA-1", "day": "2020-12-06", "statusType": "INCOMPLETE", "total": 2 // we have C13-TBX4 + C14-TBX4, dates are overlapping }, { "studyId": "TBX4", "siteId": "USA-1", "day": "2020-12-07", "statusType": "INCOMPLETE", "total": 1 // we have C14-TBX4 }, ]
The above is just the example for the statusType: INCOMPLETE
but the same logic needs to be done for the other statuses.
As you see the goal is to map a new array based on single dates in a range of dates and add the total of how many ids are in that status on that day by a single day.
I do not include any snippets as honestly have no idea where to start and how to do it
Advertisement
Answer
If I understand properly, we’re given studies that contain a range of days, and we’re given a list of specific dates that the studies’ ranges encompass. We want to produce study objects that indicate the specific day each contains, and do a little totaling based on matching days and types.
const data = [ { id: "C12-TBX4", studyId: "TBX4", siteId: "USA-1", statusType: "INCOMPLETE", statusFrom: "2020-12-01", statusTo: "2020-12-05" }, { id: "C13-TBX4", studyId: "TBX4", siteId: "USA-1", statusType: "INCOMPLETE", statusFrom: "2020-12-03", statusTo: "2020-12-07" }, { id: "C14-TBX4", studyId: "TBX4", siteId: "USA-1", statusType: "INCOMPLETE", statusFrom: "2020-12-05", statusTo: "2020-12-08" }, { id: "C16-TBX4", studyId: "TBX4", siteId: null, statusType: "REJECTED", statusFrom: "2020-12-05", statusTo: "2020-12-09" }, { id: "C17-TBX4", studyId: "TBX4", siteId: null, statusType: "REJECTED", statusFrom: "2020-12-05", statusTo: "2020-12-09" }, { id: "C18-TBX4", studyId: "TBX4", siteId: "USA-1", statusType: "DROPOUT", eligible: true, statusFrom: "2020-12-05", statusTo: "2020-12-09" }, { id: "C19-TBX4", studyId: "TBX4", siteId: "USA-1", statusType: "DROPOUT", eligible: false, statusFrom: "2020-12-05", statusTo: "2020-12-10" } ]; const rangeOfDates = [ new Date("2020-12-01T00:00:00.000Z"), new Date("2020-12-02T00:00:00.000Z"), new Date("2020-12-03T00:00:00.000Z"), new Date("2020-12-04T00:00:00.000Z"), new Date("2020-12-05T00:00:00.000Z"), new Date("2020-12-06T00:00:00.000Z"), new Date("2020-12-07T00:00:00.000Z"), new Date("2020-12-08T00:00:00.000Z"), new Date("2020-12-09T00:00:00.000Z") ]; // prepare input objects for search by date let studies = data.map((s) => { let r = Object.assign({}, s); // getTime() gives scalar ms since the epoch, for simpler comparisons r.statusFrom = new Date(r.statusFrom).getTime(); r.statusTo = r.statusTo ? new Date(r.statusTo).getTime() : 8640000000000000; return r; }); // same for the times let times = rangeOfDates.map((d) => { let time = d.getTime(); let day = d.toISOString().split("T")[0]; // the day part of the string return { time, day }; }); let resultIndex = {}; times.forEach((t) => { // get the matching studies, recall that t is an epoch time and a day string let matchingStudies = studies.filter(s => { return s.statusFrom <= t.time && t.time < s.statusTo; }); let idIndex = {}; // particularize the matching studies with the matching day, and requiring a unique studyId-day matchingStudies.forEach(ms => { let r = { day: t.day, studyId: ms.studyId, siteId: ms.siteId, statusType: ms.statusType, total: 0 }; // require uniqueness of studyId-day, second input prevails let key = `${r.day}${r.studyId}`; idIndex[key] = r; }); matchingStudies = Object.values(idIndex); // summarize totals by statusType-day matchingStudies.forEach(ms => { let key = `${ms.day}${ms.statusType}`; if (!resultIndex[key]) resultIndex[key] = ms; resultIndex[key].total++; }) }); let result = Object.values(resultIndex); console.log(result);