'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:
but i want it to look like this:
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 |


