Skip to content

Instantly share code, notes, and snippets.

@benbrandt22
Last active November 6, 2023 20:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save benbrandt22/17d2078c06f9adc326e37bc374bd4072 to your computer and use it in GitHub Desktop.
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
<!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