1

I am new in JavaScript and programming. I get data via AJAX. I want to re-generate it to get a nested object grouped by part of the data. In this case I want it grouped by year and month

Here is my data and my function:

myObj = [
    	  {"date":'2019-06-05',"name":"abc 0"},
    	  {"date":'2019-06-01',"name":"abc 1"},
    	  {"date":'2019-05-25',"name":"abc 2"},
    	  {"date":'2019-05-15',"name":"abc 3"},
    	  {"date":'2020-06-30',"name":"abc 4"},
    	  {"date":'2020-06-25',"name":"abc 5"},
    	  {"date":'2020-05-28',"name":"abc 6"},
    	  {"date":'2020-05-26',"name":"abc 7"}
            ];

function regenerate(data) {
  var result = {
    "allyears": [{}]
  };
  for (x = 0; x < data.length; x++) {
    var year = data[x].date.slice(0, 4);
    var month = data[x].date.slice(5, 7);

    if (!result.allyears.months) {
      result.allyears['year'] = year;
      result.allyears.months = [{}];
    }
    if (!result.allyears.months.data) {
      result.allyears.months['month'] = month;
      result.allyears.months.data = [{}];
    }
    result.allyears.months.data[x] = data[x];
  }
  console.log(result);
  return result;
};

regenerate(myObj);

Result I expect:

{
  "allyears": [{
    "year": "2019",
    "months": [{
      "month": "06",
      "data": [{
          "date": '2019-06-05',
          "name": "abc 0"
        },
        {
          "date": '2019-06-01',
          "name": "abc 1"
        }
      ]
    }, {
      "month": "05",
      "data": [{
          "date": '2019-05-25',
          "name": "abc 2"
        },
        {
          "date": '2019-05-15',
          "name": "abc 3"
        },
      ]
    }]
  }]
};

What am I missing in my function?

4
  • should result.allyears.months = [{}]; not be result.allyears['year'].months = [{}];, or something along those lines to put your months inside your object? Also an actual outcome next to your expected outcome would be nice. Commented Jun 20, 2019 at 12:17
  • Side note, your question has nothing to do with JSON. JavaScript Object Notation is a serialization format (a way to represent data as text) which is likely used to communicate between your application and the service it's calling, but once you're handling the data in your application it's just JavaScript objects. [] is an empty javascript array, the "[]" string can be parsed as the JSON representation of an empty array. Commented Jun 20, 2019 at 12:30
  • @Aaron I edited the question in part to remove all the JSON references when there was no JSON. I had apparently missed the title and the tags. I am as annoyed as you at the wrong terms being used when they don't apply. Do feel free to edit any posts that use the wrong terminology in order to improve them, though. Commented Jun 20, 2019 at 12:38
  • If any one updates my code, then it will be very helpful for my knowledge. Commented Jun 20, 2019 at 12:45

1 Answer 1

1

Probably not the cleverest solution, but it should do the job "beautifully". The routine is taking the advantage of Array.reduce, where an initial accumulator (in this case an empty array) is used and, while looping the original myObj array, it checks whether:

  • The year element exists in the array. If it doesn't it creates it.
  • The month element exists in the year element. If it doesn't it creates it.
  • Once everything is created, it adds data to the current month.

I will add some comments to the snippet below for further explanations, the output, to me, seems okay.

const myObj = [
      {"date":'2019-06-05',"name":"abc 0"},
      {"date":'2019-06-01',"name":"abc 1"},
      {"date":'2019-05-25',"name":"abc 2"},
      {"date":'2019-05-15',"name":"abc 3"},
      {"date":'2020-06-30',"name":"abc 4"},
      {"date":'2020-06-25',"name":"abc 5"},
      {"date":'2020-05-28',"name":"abc 6"},
      {"date":'2020-05-26',"name":"abc 7"}
];

let res = {
  allyears: myObj.reduce((acc, next) => {
    let [year, month, day] = next.date.split('-');
    // ^-- Acquire year, month and day (actually, day is not needed) from the original date string.
    let yearRef = acc.find(i => i.year === year);
    // ^-- checks whether the current year already exists in the array.
    if (!yearRef) acc.push({year}), yearRef = acc[acc.length - 1];
    // ^-- if it doesn't, it creates it and fill the above reference of it.
    yearRef.months = yearRef.months || [];
    // ^-- same as the year above, but with month.
    let monthRef = yearRef.months.find(i => i.month === month);
    if (!monthRef) yearRef.months.push({month}), monthRef = yearRef.months[yearRef.months.length - 1]// ^-- same as above, with month.
    monthRef.data = (monthRef.data || []).concat(next);
    // ^-- once the month element is available, add the next element to data. If data does not yet exist, init it.
    return acc;
  }, [])
};

console.log(res);

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

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.