Last active
November 6, 2023 20:18
-
-
Save benbrandt22/17d2078c06f9adc326e37bc374bd4072 to your computer and use it in GitHub Desktop.
JSON Objects Analysis Tool - From an array of objects, this tells you about properties and their values
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>JSON Analysis</title> | |
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script> | |
<!-- I am not a javascript developer. I built a similar tool in C# and wanted to make it easier to share as a JS app. Most of this was built with the help of Chat GPT with some small adjustments by me. As a POC it works, but could probably be refactored to be better :-) --> | |
</head> | |
<body> | |
<h1>JSON Analysis</h1> | |
<div id="app"> | |
<label for="jsonInput">JSON Array:</label><br> | |
<textarea id="jsonInput" rows="10" cols="80" v-model="jsonArray" spellcheck="false" placeholder="[Paste a JSON array of objects here to analyze]"></textarea><br><br> | |
<button @click="analyzeJSON">Analyze</button> | |
<div id="resultDiv"> | |
<h3>Properties:</h3> | |
<ol style="column-count: 4;"> | |
<li v-for="(info, prop) in propertyInfo" :key="prop" > | |
<a :href="`#prop_${prop}`">{{prop}}</a> | |
</li> | |
</ol> | |
<div v-for="(info, prop) in propertyInfo" :key="prop"> | |
<h3 :id="`prop_${prop}`">{{ prop }}</h3> | |
<ul> | |
<li>Type: {{ info.type }}</li> | |
<li>Objects with property: {{ info.count }} ({{ getPercentage(info.count, totalObjects) }}%)</li> | |
<li>Objects with property set to null: {{ info.countNull }} ({{ getPercentage(info.countNull, totalObjects) }}%)</li> | |
<li>Total unique values: {{ info.uniqueValues.length }}</li> | |
<li>All property values are unique: {{ areArraysEqualLength(info.uniqueValues, info.allValues) }}</li> | |
<li v-if="info.type === 'number'">Value range: {{ info.min }} - {{ info.max }}</li> | |
<li>Most common Values: | |
<ul> | |
<li v-for="(count, value, index) in getSortedValueCounts(info.valueCounts)" :key="value" v-if="index < 10"> | |
<span v-if="typeof value === 'object'">{{ JSON.stringify(value) }}</span> | |
<span v-else>{{ value }}</span> | |
({{ count }} - {{ getPercentage(count, totalObjects) }}%) | |
</li> | |
</ul> | |
</li> | |
</ul> | |
</div> | |
</div> | |
</div> | |
<script> | |
new Vue({ | |
el: '#app', | |
data: { | |
jsonArray: '', | |
propertyInfo: {}, | |
totalObjects: 0 | |
}, | |
methods: { | |
analyzeJSON() { | |
try { | |
this.propertyInfo = {}; | |
var data = JSON.parse(this.jsonArray); | |
if (!Array.isArray(data)) { | |
throw new Error('JSON must be in the form of an array'); | |
} | |
this.jsonArray = ""; // reset the text area | |
this.totalObjects = data.length; | |
// Iterate through each object in the array | |
for (var i = 0; i < this.totalObjects; i++) { | |
var obj = data[i]; | |
// Iterate through each property of the object | |
for (var prop in obj) { | |
if (obj.hasOwnProperty(prop)) { | |
// Track property information | |
if (!this.propertyInfo[prop]) { | |
this.propertyInfo[prop] = { | |
expanded: false, | |
type: typeof obj[prop], | |
count: 0, | |
countNull: 0, | |
allValues: [], | |
uniqueValues: [], | |
min: null, | |
max: null, | |
valueCounts: {} | |
}; | |
} | |
// Count the objects with the property defined | |
this.propertyInfo[prop].count++; | |
// Check if the property value is null | |
if (obj[prop] === null) { | |
this.propertyInfo[prop].countNull++; | |
} | |
// aggregates all values for each property | |
this.propertyInfo[prop].allValues.push(obj[prop]); | |
// and then keep an array of the unique values... | |
if (!this.propertyInfo[prop].uniqueValues.includes(obj[prop])) { | |
this.propertyInfo[prop].uniqueValues.push(obj[prop]); | |
} | |
// Check if the property value is a number | |
if (typeof obj[prop] === 'number') { | |
if (this.propertyInfo[prop].min === null || obj[prop] < this.propertyInfo[prop].min) { | |
this.propertyInfo[prop].min = obj[prop]; | |
} | |
if (this.propertyInfo[prop].max === null || obj[prop] > this.propertyInfo[prop].max) { | |
this.propertyInfo[prop].max = obj[prop]; | |
} | |
} | |
// Count the occurrences of each property value | |
var propertyValue = obj[prop]; | |
if(typeof propertyValue === 'object'){ | |
// treat object as a JSON string for display & comparison purposes | |
propertyValue = JSON.stringify(propertyValue); | |
} | |
if (!this.propertyInfo[prop].valueCounts[propertyValue]) { | |
this.propertyInfo[prop].valueCounts[propertyValue] = 1; | |
} else { | |
this.propertyInfo[prop].valueCounts[propertyValue]++; | |
} | |
} | |
} | |
} | |
} catch (error) { | |
console.error('Invalid JSON input:', error); | |
alert('Invalid JSON input. Please provide a valid JSON array.'); | |
} | |
}, | |
getPercentage(count, total) { | |
return ((count / total) * 100).toFixed(2); | |
}, | |
areArraysEqualLength(arr1, arr2) { | |
return arr1.length === arr2.length; | |
}, | |
getSortedValueCounts(valueCounts) { | |
return Object.entries(valueCounts) | |
.sort((a, b) => b[1] - a[1]) | |
.reduce((sortedObj, [value, count]) => { | |
sortedObj[value] = count; | |
return sortedObj; | |
}, {}); | |
} | |
} | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment