1

Here's a geojson object, which has array of features, each feature has a properties object.

I understand that there are many question related to map arrays and objects but I couldn't find a similar case. I tried to use lodash map and groupBy to map the properties and group the values under their key but honestly I just don't know what the combination of functions should be.

I can get the property name part by doing the following:

// since properties are the same for all features
// I extract them alone first

let properties = Object.keys(features[0].properties)

properties.map(Prentelement =>
{
    let formated = {
        // this gives me the first part
        propertyName: Prentelement,

        // I can't figure out this part to map the values uniquely under
        children: [
          {
            value: "alex"
          },
          {
            value: "cairo"
          }
        ]
    }

    return formated;
})

This is an example of the input format:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "Name": "cairo",
        "Type": "Province"
      }
    },
    {
      "type": "Feature",
      "properties": {
        "Name": "alex",
        "Type": "Province"
      }
    }
  ]
}

And what I want to do is a kind of summary on each available property and their possible values across different features. Please note that a value can be repeated across features but I want it available only once in the end result. So result would be an array like this:

[
  {
    propertyName: "Name",
    children: [
      {value: "alex"},
      {value: "cairo"}
    ]
  },
  {
    propertyName: "Type",
    children: [
      {value: "Province"}
    ]
  }
]
Shidersz
  • 16,846
  • 2
  • 23
  • 48
Ibrahim Mohammed
  • 302
  • 5
  • 17
  • Would a simpler output like the following be acceptable? `{ "Name": ["alex", "cairo"], "Type": ["Province"] }` ? – user7290573 Jul 11 '19 at 16:13
  • @user7290573 unfortunately no, i need the format like in the example for " ant design " cascader component https://ng.ant.design/components/cascader/en – Ibrahim Mohammed Jul 11 '19 at 16:16

2 Answers2

1

Here you have one solution using first Array.reduce() to group the features array by the properties on an object. Note we use Sets to keep unique values only. Later, on a second step, we can Array.map() the entries of the previously generated object to get the desired structure:

let input = {
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {"Name": "cairo", "Type": "Province"}
    },
    {
      "type": "Feature",
      "properties": {"Name": "alex", "Type": "Province"}
    }
  ]
};

// Step 1, group feature values by property.

let out = input.features.reduce((acc, {properties}) =>
{
    Object.entries(properties).forEach(([key, val]) =>
    {
        acc[key] = acc[key] || new Set();
        acc[key].add(val);
    });

    return acc;
}, {});

// Show the generated object on Step 1.

console.log("Step 1 - After grouping:", out);

for (const key in out)
{
    console.log(`${key} => ${[...out[key]]}`);
}

// Step 2, map the entries of the generated object.

out = Object.entries(out).map(([k, v]) =>
    ({PropertyName: k, Children: [...v].map(x => ({Value: x}))})
);

console.log("Step 2 - After mapping:", out);
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}

Other documentation you may need to read:

Shidersz
  • 16,846
  • 2
  • 23
  • 48
  • wow, thank you so much, hopefully i will be able to understand how it works step by step – Ibrahim Mohammed Jul 11 '19 at 16:39
  • 1
    @IbrahimMohammed I have added a log of the intermediate structure and links to additional documentation in case you need it. Hope this helps you to understand the code in a better way. – Shidersz Jul 11 '19 at 18:09
1

Another approach (using same input data provided by @Shidersz):

     const result = input.features.reduce((acc, feature) => { 
             Object.keys(feature["properties"]).forEach(key => {
                 const index = acc.findIndex(property => {
                     return property["propertyName"] === key })

                 if (index === -1) {
                      acc.push({ propertyName: key, children: [ { value: feature["properties"][key]}] })
                 } else {
                      if (acc[index].children.findIndex(child => child.value === feature["properties"][key]) === -1) {
                        acc[index].children.push({ value: feature["properties"][key] })
                      }

                 }
             })

          return acc;

      }, []);

     console.log(JSON.stringify(result));