2

I have an array-snapshot out of Firebase, which contains the entries of my application. Among other information there is a a timestamp called "referenceDate":

entry [0] { referenceDate: 2017-08-03,...
entry [1] { referenceDate: 2017-08-02,...
entry [2] { referenceDate: 2017-08-01,...
entry [3] { referenceDate: 2017-07-03,...
entry [4] { referenceDate: 2017-07-02,...

I want to output the entries grouped under a headline by month and year like this

08.2017
03.08.2017
02.08.2017
01.08.2018
07.2017
03.07.2017
02.07.2017

My idea is to loop over the array-snapshot and create another nested one which looks like this:

 {"monthYear": "08.2017":[
    {"referenzDatum": 2017-08-03},... },
    {"referenzDatum": 2017-08-02},... },
    {"referenzDatum": 2017-08-01},... },]},
 {"monthYear": "07.2017":[
    {"referenzDatum": 2017-07-03},... },
    {"referenzDatum": 2017-07-02},... }, ...]}

Then loop over it with two nested ngFor to generate the html output.

Is there a simple way to achieve this? I tried to just push the old entry into the new array according to the corresponding monthyear whenever this changes, but that didnt work out, because references were copied. then I tried the following code, but it doesn't really work for more than 2 different months and the code just looks awful.

var oldDate: string;
var newDate: string;
sortedLogLine.entries = [];
this.sortedLog = [];

for (var i = 0; i < entries.length; i++) {
  newDate = entries[i].referenceDate.substring(0, 7).split('-').reverse().join('.');
  if (oldDate == newDate) {
    sortedLogLine.entries.push(entries[i]);
  }
  if (!oldDate) {
    sortedLogLine.entries.push(entries[i]);
    sortedLogLine.monthYear = newDate;
    oldDate = newDate;
  }
  if (oldDate != newDate) {

    pushSortedLogLine.entries = sortedLogLine.entries.slice(0);
    pushSortedLogLine.monthYear = oldDate;
    this.sortedLog.push(pushSortedLogLine);

    sortedLogLine.entries = [];
    sortedLogLine.entries.push(entries[i]);
    sortedLogLine.monthYear = newDate;
    oldDate = newDate;
  }
}
this.sortedLog.push(sortedLogLine);

Any suggestions as to how to do this more efficiently?

1

5 Answers 5

1

The usual way to do something like this would be groupBy. Javascript doesn't have a native groupBy method on its Arrays, but several helper libraries like underscore.js do. Alternatively, you can roll your own with reduce:

let getMonthYear = (obj) => obj.referenceDate.split('-').reverse().slice(1).join('.');

let groupBy = (ary, fn) => ary.reduce(function(groups, item) {
       let key = fn(item)
       if (!groups[key]) groups[key]=[]
       groups[key].push(item)
       return groups;
   }, {});

let entries = [ { referenceDate: '2017-08-03' },
                { referenceDate: '2017-08-02' },
                { referenceDate: '2017-08-01' },
                { referenceDate: '2017-07-03' },
                { referenceDate: '2017-07-02' } ]
let groups = groupBy(entries, getMonthYear);
console.log(groups)

which produces this output:

{ '08.2017': 
   [ { referenceDate: '2017-08-03' },
     { referenceDate: '2017-08-02' },
     { referenceDate: '2017-08-01' } ],
  '07.2017': 
   [ { referenceDate: '2017-07-03' },
     { referenceDate: '2017-07-02' } ] }

See also this similar question.

Sign up to request clarification or add additional context in comments.

Comments

1
 var arrayOfDates = [
      {'referenceDate':'2017-08-03'},
      {'referenceDate':'2017-08-02'},
      {'referenceDate':'2017-08-01'},
      {'referenceDate':'2017-07-03'},
      {'referenceDate':'2017-07-02'}
   ];
  var result = [];

arrayOfDates.forEach(function(entry) {
    var date = new Date(entry.referenceDate);

    var day = date.getDate();
    var monthIndex = date.getMonth() +1;
    var year = date.getFullYear();

    var keyDateFormat = monthIndex+'.'+year;

    if(!(keyDateFormat in result)) {
        result[keyDateFormat] = [];
    }
    result[keyDateFormat].push(entry);
});

Comments

0

Have a look at Lodash, specifically groupBy

I believe Lodash is a better choice over Underscore.js, more details in this blog post

Comments

0

Probably use a hash table:

var timetable = {};

data.forEach(function(el){
  var d = new Date(el.referenceDate),
  y = d.getFullYear(),
  m = d.getMonths() +1;

  if(!timetable[y]) timetable[y] = [];
  if(!timetable[y][m]) timetable[y][m] = [];

  timetable[y][m].push(el);
});

Then you can get all available years, sort and display them:

Object.values(timetable).sort((a,b)=>a-b).forEach(function(year){
  console.log(year);
  for(var [month,entries] of timetable[year].entries()){
     console.log(month,entries.join("\n"));
  }
});

Comments

0

Try this:

const entries = [{ referenceDate: '2017-08-03'}, { referenceDate: '2017-08-02'}, { referenceDate: '2017-08-01'}, { referenceDate: '2017-07-03'}, { referenceDate: '2017-07-02'}]; 
const resultObj = {};

for (var i = 0; i < entries.length; i++) {
  const month = entries[i].referenceDate.substring(0, 7).split('-').reverse().join('.');
  if (!resultObj[month]) {
  	resultObj[month] = [];
  }
  resultObj[month].push(entries[i]);
}

const out = document.getElementsByClassName('json')[0];
out.innerHTML = JSON.stringify(resultObj, undefined, 2);
<pre class="json"></pre>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.