'Sorting json objects into groups based on a property value [closed]

I am very new to javascript/react and json - so if this seems basic, i apologize. I have been struggling to get this accomplished.

I have a json structure that comes across a websocket and what I would like to do is parse all the json keys into separate lists based on the "meta.group" property. I dont know any group info until the json structure comes acorss. could be 1 group or 100. So therefor the number of lists i need has to be dynamic. I then display the groups via HTML.

I currently read the properties and display them individually but would like to display them by their grouping.

What is the best way to accomplish this ?

My json looks like this:

{
    "Hello": {
        "value": "World",
        "meta": {
            "type": "string",
            "description": "tester",
            "group": "A",
            "readOnly": true
        }
    },
    "Count1": {
        "value": 2,
        "meta": {
            "type": "number",
            "description": "tester",
            "group": "B",
            "readonly": false,
            "min": "0",
            "max": "100"
        }
    },
    "Count2": {
        "value": "2",
        "meta": {
            "type": "number",
            "description": "tester",
            "group": "C",
            "readonly": false,
            "min": "0.0",
            "max": "100"
        }
    },
    "Control1": {
        "value": "World",
        "meta": {
            "type": "string",
            "description": "tester",
            "group": "A",
            "readOnly": true
        }
    },
    "Count3": {
        "value": 2,
        "meta": {
            "type": "number",
            "description": "tester",
            "group": "A",
            "readonly": false,
            "min": "0",
            "max": "100"
        }
    }

My current react function code block:

export default function ConfigEdit({data, handleSubmit, setFileContent}) {
    const [jsonData, setJsonData] = useState(data)
 

    const handleEditSubmit = ()=>{
        console.log(data);
        const new_file = new Blob([JSON.stringify(jsonData,undefined,4)], {
            type: 'application/json'
          });
        setFileContent(JSON.stringify(jsonData, undefined, 4))
        handleSubmit(new_file);
    }

    const editValue = ({name,data}) =>
    {
        var temp = jsonData;
        temp[name].value = data;
        console.log(data)
        setJsonData(temp)
    }

    const ConfigPanel = () =>{
        const items = Object.keys(jsonData)

        return(
            items.map((member,index)=>{
                //if there's no meta field, then skip
                if (jsonData[member].hasOwnProperty('meta') === false)
                {
                    console.log(`no meta field in {member}`)
                    return <></>
                }
                //if there is a meta field that is empty, also skip
                else if(member.meta === "")
                {
                    return <></>
                }
                else
                {
                    {/* THIS SECTION NEEDS CHANGING - create lists for each group and then output HTML blocks for each group with members.  */}
                    let groupName = jsonData[member].meta.group
                    if(groupName != null){
                        return(
                            <div style={{display:"flex", border: "1px black solid", marginBottom: "10px"}}>
                                <div style={{flex:2, margin: "10px"}}>
                                    GROUP: {groupName}
                                </div>
                                <div style={{flex:4, margin: "10px"}}>
                                    <ConfigParam 
                                    editValue={editValue} 
                                    key={index} 
                                    name={member} 
                                    type={jsonData[member].meta.type} 
                                    value={jsonData[member].value} 
                                    description={jsonData[member].meta.description} 
                                    meta={jsonData[member].meta}/>
                                </div>
                            </div>
                        )
                    }
                }
            })
        )
    }
    
    return (
        <Form>
            <Form.Group>
                <div style={{margin: "10px"}}>
                    <ConfigPanel />
                </div>
                <hr></hr>
                <Button className="btn-green" onClick={handleEditSubmit}>Save</Button>
            </Form.Group>
        </Form>
    )
}

Current look is this:

enter image description here

but i want it to look like this:

enter image description here



Solution 1:[1]

Here is my updated answer.

It may not be the optimal way, but the idea is to separate the creation of a more sensible object shape for the grouping and the rendering of headers and children.

const result = Object.entries(data).reduce(
  (acc, [key, value]) => {
    const group = value.meta.group;

    if (group) {
      acc[group] = {
        ...(acc[group] ?? {}),
        [key]: value
      };
    }

    return acc;
  },
  {}
);

Notice that I did not use an array on the accumulated value(acc), because in my opinion, it's better to extract them later with Object.entries

Check the complete solution here, and how I added the render functions.

https://codesandbox.io/s/priceless-meadow-hk8sxq?file=/src/App.tsx

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1