Home > Software engineering >  JSON group elements by value
JSON group elements by value

Time:06-08

Good morning,

I'm trying to create a JSON file with all Portuguese parishes inserted in each municipality that is inserted in each respective district - so it's a pretty basic structure,

The structure I intend to have is as follows:

{
  "district": "Aveiro",
  "OfficialCodeDistrict": "01",
  "municipalities": [
    {
      "municipality": "Arouca",
      "OfficialCodeMunicipality": "0104",
      "parishes": [
        {
          "parish": "Fermedo",
          "OfficialCodeParish": {}
        },
        {
          "parish": "Várzea",
          "OfficialCodeParish": "010420"
        },
        {
          "parish": "Escariz",
          "OfficialCodeParish": "010409"
        },
        {
          "parish": "Mansores",
          "OfficialCodeParish": "010413"
        }
      ]
    },
    {
      "municipality": "Águeda",
      "OfficialCodeMunicipality": "0101",
      "parishes": [
        {
          "parish": "Fermentelos",
          "OfficialCodeParish": "010109"
        },
        {
          "parish": "Préstimo e Macieira de Alcoba",
          "OfficialCodeParish": "010127"
        }
      ]
    }
  ]
}

So each district contains all municipalities which, within each municipality, we have all parishes.

I started working on top of a JSON that was a result of an Excel export which can be found here

Upon reading this question (https://stackoverflow.com/a/54756327) I was able to to transform my JSON to group municipalities inside each district, as you can see in the image below:

JSON Output

The only problem here is that I still need to make a second grouping which is grouping municipalities within each district - as you can see in the image, I'm displaying two results where the parishes are both from the Vale de Cambra municipality whereas I'd like to have each municipality contain all parishes in the same way the districts are holding all results per district.

This is the code that allowed me to group the districts (which has the same format as the StackOverflow question I pasted above)

const result = Object.entries(locations.reduce((acc, { OfficialCodeDistrict, OfficialNameDistrict, OfficialCodeMunicipality, OfficialNameMunicipality, OfficialNameParish, Type  }) => {
        acc[OfficialNameDistrict] = (acc[OfficialNameDistrict] || []);
        acc[OfficialNameDistrict].push({ OfficialCodeDistrict, OfficialCodeMunicipality, OfficialNameMunicipality, OfficialNameParish, Type });
        return acc;
    }, {})).map(([key, value]) => ({ district: key, municipalities: value }));

    console.log(result);

And I've tried doing some sort of a loop (this may look super wrong but I'm still learning on how to manipulate objects in JavaScript) to try to loop the municipalities with the same name within each district

let counter = 0;

// I'm going to create a loop to see if I can access all municipalities and them with the method above
while (counter < result.length){

    // Iterating each district on the console - this way we can access each one to make the changes above, I'm hoping
    result2 = Object.entries(result[counter]['municipalities'].reduce((acc, { OfficialCodeMunicipality, OfficialNameMunicipality, OfficialNameParish, Type  }) => {
        acc[OfficialNameMunicipality] = (acc[OfficialNameMunicipality] || []);
        acc[OfficialNameMunicipality].push({ OfficialCodeMunicipality, OfficialNameParish, Type });
        return acc;
    }, {})).map(([key, value]) => ({ municipality: key, parishes: value }));

    console.log(result2);

    // I'm being able to loop the municipalities but what is happening is, it's iterating one JSON object per district
    // example: Portalegre is generating a JSON object with 15 entries and every other district is doing the same, we're on the good but still not working

    counter  ;
}

Which is iterating and creating one JSON object per district with its respective municipalities - so it is working well but I don't know how to push these results to the first object I created in order to have everything organized

Output Per District

Can you help me in arranging the JSON object the way I want it? I know (or it seems like it, at least) there's only a simple step missing somewhere for me to be able to push these individual iterations into the original object, into each district, but I'm kind of clueless, right now,

Thank you very much in advance!

CodePudding user response:

you can do something like this

Basically you create an object with district as key and foreach district you create an object for the municipality with municipality name as key

after you complete parsing the data you jest get rid of the indices using Object.values

const transform  = data => Object.values(data.reduce((res, item) => {
  const district = item['Official Name District']
  const municipality = item['Official Name Municipality']
  const existingDistrict = res[district] || {district, OfficialCodeDistrict: item['Official Code District'], municipalities: {} }
  const existingMunicipality = existingDistrict.municipalities[municipality] || {municipality, OfficialCodeMunicipality: item['Official Code Municipality'], parishes:[]}
  
  return {
   ...res,
   [district]: {
     ...existingDistrict,
     municipalities: {    
       ...existingDistrict.municipalities,
       [municipality]: {
       ...existingMunicipality,
       parishes: [...existingMunicipality.parishes, {parish: item['Official Name Parish'], OfficialCodeParish: item['Official Code Parish']}]
       }
     }
   }
  }
  
}, {})).map(d => ({...d, municipalities: Object.values(d.municipalities)}))


const data = [
{
"Official Code District": "01",
"Official Name District": "Aveiro",
"Official Code Municipality": "0104",
"Official Name Municipality": "Arouca",
"Official Code Parish": "010411",
"Official Name Parish": "Fermedo",
"Type": "parish"
},
{
"Official Code District": "01",
"Official Name District": "Aveiro",
"Official Code Municipality": "0109",
"Official Name Municipality": "Santa Maria da Feira",
"Official Code Parish": "010913",
"Official Name Parish": "Lourosa",
"Type": "parish"
},
{
"Official Code District": "01",
"Official Name District": "Aveiro",
"Official Code Municipality": "0109",
"Official Name Municipality": "Santa Maria da Feira",
"Official Code Parish": "010914",
"Official Name Parish": "Milheirós de Poiares",
"Type": "parish"
},
{
"Official Code District": "01",
"Official Name District": "Aveiro",
"Official Code Municipality": "0111",
"Official Name Municipality": "Mealhada",
"Official Code Parish": "011107",
"Official Name Parish": "Vacariça",
"Type": "parish"
},
{
"Official Code District": "01",
"Official Name District": "Aveiro",
"Official Code Municipality": "0118",
"Official Name Municipality": "Vagos",
"Official Code Parish": "011801",
"Official Name Parish": "Calvão",
"Type": "parish"
},
{
"Official Code District": "01",
"Official Name District": "Aveiro",
"Official Code Municipality": "0119",
"Official Name Municipality": "Vale de Cambra",
"Official Code Parish": "011906",
"Official Name Parish": "Macieira de Cambra",
"Type": "parish"
},
{
"Official Code District": "01",
"Official Name District": "Aveiro",
"Official Code Municipality": "0119",
"Official Name Municipality": "Vale de Cambra",
"Official Code Parish": "011907",
"Official Name Parish": "Roge",
"Type": "parish"
},
{
"Official Code District": "02",
"Official Name District": "Beja",
"Official Code Municipality": "0204",
"Official Name Municipality": "Barrancos",
"Official Code Parish": "020401",
"Official Name Parish": "Barrancos",
"Type": "parish"
},
{
"Official Code District": "02",
"Official Name District": "Beja",
"Official Code Municipality": "0206",
"Official Name Municipality": "Castro Verde",
"Official Code Parish": "020605",
"Official Name Parish": "São Marcos da Ataboeira",
"Type": "parish"
}]

console.log(transform(data))

  • Related