Skip to content
Advertisement

How to map data to a new array with specific fields and values and add a single object per day based on a range of dates

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);
User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement