Reduce flat array to 2-level nested json object array

Keywords´╝Ü javascript json nested reduce

Question: 

I have the following flat array:

{ "State": "New York", "Name": "Jane", "Product": "Apple" },
{ "State": "New York", "Name": "Jill", "Product": "Banana"},
{ "State": "California", "Name": "Jill", "Product": "Apple" },
{ "State": "California", "Name": "Jill", "Product": "Banana"}

Is it possible to create a 2-level nested array (i.e., Name > nested State Array > nested Product Array)? It would look like as follows:

{
  "Name": "Jill",
  "States": [
   {
   "State": "California",
   "Products": [
      {
    "Product": "Apple"
      },
      {
          "Product": "Banana"
      }
    ]
   },
   {
   "State": "New York",
   "Products": [
      {
          "Product": "Banana"
      }
    ]
   }
  ]
 },
 {
  "Name": "Jane",
  "States": [
   {
   "State": "New York",
   "Products": [
     {
      "Product": "Apple"
     }
    ]
   }
  ]
 }

I have been able to get one level nested (States). How would you nest the second level?

Here is a stackblitz: https://stackblitz.com/edit/angular-lu6zj2

this.grouped_data = this.data.reduce((data, item) => {
  data[item.Name] = data[item.Name] || { Name: item.Name, States: []}
  data[item.Name].States.push(item) 
  return data;
}, {})

Answers: 

let data = [
  { "State": "New York", "Name": "Jane", "Product": "Apple" },
  { "State": "New York", "Name": "Jill", "Product": "Banana"},
  { "State": "California", "Name": "Jill", "Product": "Apple" },
  { "State": "California", "Name": "Jill", "Product": "Banana"}
];

let grouped = data.reduce((p, n) => {
  if (!p[n.Name]) p[n.Name] = { States: [] };
  if (!p[n.Name].States.some(state => state.State === n.State)) {
    p[n.Name].States.push({ State: n.State, Products: [n.Product] });
  } else {
    !p[n.Name].States.find(state => state.State === n.State).Products.push(n.Product);
  }
  return p;
}, {});

console.log(grouped);

After that you can also remove duplicated products if you want to. I'll let you deal with it !