bier hier
bier hier

Reputation: 22530

How to create a json grouped by date in js?

I have an array of objects sorted by date:

const alerts = [{ 
    id: 1, date: '2018-10-31T23:18:31.000Z', name: 'Joke', title: 'this is the first 1' 
}, { 
    id: 2, date: '2018-10-30T23:18:31.000Z', name: 'Mark', title: 'this is the second one' 
}]

I am trying to 'group' the alerts by date so trying to create 'datesections' which have a dateheader, the result should be something like:

const sections = [{
   date: '2018-10-31T23:18:31.000Z',
   heading: 'today',
   alerts: [{ id: 1, date: '2018-10-31T23:18:31.000Z', name: 'Joke', 
   title: 'this is the first one' }]
}, {
   date: '2018-10-30T23:18:31.000Z',
   heading: 'Yesterday',
   alerts: [{ id: 2, date: '2018-05-30T23:18:31.000Z', name: 'Mark', 
   title: 'this is the second one' }]
}]

I tried something this but can't figure out how to get the alerts with the same date in the alerts prop:

const sections2=alerts.map(a =>
    ({
        date: a.date,
        heading:'today new',
        alerts:alerts
    })
)

Upvotes: 1

Views: 2920

Answers (5)

user10480519
user10480519

Reputation: 14

Maybe you need something like this? Didn't have much time for this and last array parsing might be done in more elegant way ;)

var alerts = [
    { id: 1, date: '2018-10-31T23:18:31.000Z', name: 'Joke', title: 'this is the first 1' },
    { id: 3, date: '2018-10-31T23:44:31.000Z', name: 'Joke1', title: 'this is the 2nd' },
    { id: 2, date: '2018-10-30T23:18:31.000Z', name: 'Mark', title: 'this is the second one' },
    { id: 4, date: '2018-10-30T23:45:31.000Z', name: 'Mark1', title: 'this is the 3rd' },
    { id: 5, date: '2018-10-27T23:18:31.000Z', name: 'Mark2', title: 'this is the 4th' },
];

var processedAlerts = [], finalAlerts;

(function(initAlerts){
    //iterate through array to make keys to group by day
    for(var i = 0; i < initAlerts.length; i++){
        processedAlerts[i] = initAlerts[i];
        //substring here can be more sophisticated - this was faster
        initAlerts[i].keyDate = initAlerts[i].date.substr(0, 10);
    }

    //supporting function to convert string to date
    //to acheve more detailed sorting that includes time
    //just use date object and use hours, minutes and/or seconds to create Date object
    function dateFromString(strDate){
        var date, tmpDate;

        //convert string to array - I assume that date format is always the same
        //yyyy-mm-dd and will become Array 0: year, 1: month, 2: day of the month
        tmpDate = strDate.split("-");

        //moths in js are zero pased so Jan is 0, Feb is 1 and so on
        //so we want to substract 1 from human readable month value to get correct date
        date = new Date(tmpDate[0], tmpDate[1]-1, tmpDate[2]);

        return date;
    }

    //function used to compare dates and passed to sort function
    function comparedates(obj1, obj2){
        var date1, date2;

        date1 = dateFromString(obj1.keyDate);
        date2 = dateFromString(obj2.keyDate);

        let comparison = 0;

        if(date1>date2){
            comparison = 1;
        } else if(date1<date2){
            comparison = -1;
        }

        //to achieve reverse just multiply comparison result by -1
        return comparison*(-1);
    }

    function getHeader(date){
        //here place logic to generate header
        //this involves comparing dates probably from keyDate

        return "temp header: " + date.toString()
    }

    //sort the array by keyDate from newest to oldest
    processedAlerts.sort(comparedates);

    //final array rebuild
    //pass here sorted array
    finalAlerts = (function(arrayAlerts){
        var aAlerts = [], k = 0;

        for(var j = 0; j < arrayAlerts.length; j++){
            //check if entry for date exists
            //if no than create it
            if(!aAlerts[k]){
                aAlerts[k] = {
                    //removed title because I asummed that each alert has unique title and put them in alerts instead
                    date: arrayAlerts[j].keyDate, //agroupped date
                    heading: getHeader(arrayAlerts[j].keyDate), //update this function to return personalized heading
                    //here you can shape the alert object how you need
                    //I just passed it as it was
                    alerts: [arrayAlerts[j]] //array with first object inside
                };
            } else {
                //add another alert to day
                aAlerts[k].alerts.push(arrayAlerts[j]) //array with first object inside
            }

            //increasing final array key
            //if there is previous entry and keys are the same for current and previous
            if(arrayAlerts[j-1] && (arrayAlerts[j].keyDate == arrayAlerts[j-1].keyDate)){
                k++;
            }
        }

        return aAlerts;

    })(processedAlerts);

})(alerts);

console.log(finalAlerts);

Upvotes: 0

Alex G
Alex G

Reputation: 1917

You can use a regular expression to match the part of the date you want and then group your data. You can add there the header you want. Hope this helps.

const alerts = [
    { id: 1, date: '2018-10-31T23:18:31.000Z', name: 'Joke', title: 'this is the first 1' },
    { id: 2, date: '2018-10-30T23:18:31.000Z', name: 'Mark', title: 'this is the second one' },
    { id: 3, date: '2018-10-30T23:14:32.000Z', name: 'Mark', title: 'this is the third one' }
];

const groupByDate = (data) => {

    return data.reduce((acc, val) => {

        const date = val.date.match(/\d{4}-\d{2}-\d{2}/g).toString();

        const item = acc.find((item) => item.date.match(new RegExp(date, 'g')));

        if (!item) acc.push({ date: val.date, alerts: [val], heading: 'some heading' });

        else item.alerts.push(val);

        return acc;

    }, []);
};

console.log(groupByDate(alerts));

Upvotes: 0

oma
oma

Reputation: 1894

From my point of view it's not really a map what you need here, map will return a new array but not what you want. You can do this with 2 for statements

let total = [];
     for (let j = 0; j < alerts.length; j++) {
          let item = alerts[j];
          let foundDate = false;
          for (let i = 0; i < total.length; i++) {
            if (total[i].date === item.date) {
              foundDate = true;
              total.alerts.push(item);
            }
          }
          if (!foundDate) {
            console.log("!found");
            total.push({
              date: item.date,
              heading: "Yesterday",
              alerts: [item]
            });
          }
        }

If you console.log yout total array, will contain what you want. If you need any other explanation pls let me know.

Upvotes: 0

Amadan
Amadan

Reputation: 198324

const alerts = [
    { id: 1, date: '2018-10-31T23:18:31.000Z', name: 'Joke', title: 'this is the first 1' },
    { id: 2, date: '2018-05-30T23:18:31.000Z', name: 'Mark', title: 'this is the second one' }
]

const grouping = _.groupBy(alerts, element => element.date.substring(0, 10))
const sections = _.map(grouping, (items, date) => ({
  date: date,
  alerts: items
}));

console.log(sections);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

Can't help you with headings - what if it's neither "today" or "yesterday"?

Upvotes: 4

liquidvapour
liquidvapour

Reputation: 41

I feel like you are asking a couple of things here. The key one is how to group by day with a date.

To do that you will first need to know how to group. This answer may help with that.

As far as how to group by day there are a number of ways to do that. Simplest I can think of is to cut off everything after the "T" in the date string and sort that.

Upvotes: 0

Related Questions