I must be missing something here, but the following code (Fiddle) returns an empty string:
var test = new Array();
test['a'] = 'test';
test['b'] = 'test b';
var json = JSON.stringify(test);
alert(json);
What is the correct way of JSON'ing this array?
JavaScript arrays are designed to hold data with numeric indexes. You can add named properties to them because an array is a type of object (and this can be useful when you want to store metadata about an array which holds normal, ordered, numerically indexed data), but that isn't what they are designed for.
The JSON array data type cannot have named keys on an array.
When you pass a JavaScript array to JSON.stringify the named properties will be ignored.
If you want named properties, use an Object, not an Array.
const test = {}; // Object
test.a = 'test';
test.b = []; // Array
test.b.push('item');
test.b.push('item2');
test.b.push('item3');
test.b.item4 = "A value"; // Ignored by JSON.stringify
const json = JSON.stringify(test);
console.log(json);
Nice explanation and example above. I found this (JSON.stringify() array bizarreness with Prototype.js) to complete the answer. Some sites implements its own toJSON with JSONFilters, so delete it.
if(window.Prototype) {
delete Object.prototype.toJSON;
delete Array.prototype.toJSON;
delete Hash.prototype.toJSON;
delete String.prototype.toJSON;
}
it works fine and the output of the test:
console.log(json);
Result:
"{"a":"test","b":["item","item2","item3"]}"
I posted a fix for this here
You can use this function to modify JSON.stringify to encode arrays, just post it near the beginning of your script (check the link above for more detail):
// Upgrade for JSON.stringify, updated to allow arrays
(function(){
// Convert array to object
var convArrToObj = function(array){
var thisEleObj = new Object();
if(typeof array == "object"){
for(var i in array){
var thisEle = convArrToObj(array[i]);
thisEleObj[i] = thisEle;
}
}else {
thisEleObj = array;
}
return thisEleObj;
};
var oldJSONStringify = JSON.stringify;
JSON.stringify = function(input){
if(oldJSONStringify(input) == '[]')
return oldJSONStringify(convArrToObj(input));
else
return oldJSONStringify(input);
};
})();
Another approach is the JSON.stringify() replacer function param. You can pass a 2nd arg to JSON.stringify() that has special handling for empty arrays as shown below.
const arr = new Array();
arr.answer = 42;
// {"hello":"world","arr":{"answer":42}}
JSON.stringify({ hello: 'world', arr }, function replacer(key, value) {
if (Array.isArray(value) && value.length === 0) {
return { ...value }; // Converts empty array with string properties into a POJO
}
return value;
});
Alternatively you can use like this
var test = new Array();
test[0]={};
test[0]['a'] = 'test';
test[1]={};
test[1]['b'] = 'test b';
var json = JSON.stringify(test);
alert(json);
Like this you JSON-ing a array.
Json has to have key-value pairs. Tho you can still have an array as the value part. Thus add a "key" of your chousing:
var json = JSON.stringify({whatver: test});
I have a json from Google pagespeed api, which needs to be exported to big query. Since BQ doesnt support the keys having - symbol, I must replace all the key names those have - char to _
Please note that I cannot perform a find and replace on entire string as the values need a - char. The json structure can be complex and I understand the only ways to do is by iterating all the keys of nested objects.
I found this https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
but could not iterate the nested json, as I cannot predetermine the json structure and all that must be dynamically decided Any pointers how to replace all chars would be great
The input JSON is here: https://drive.google.com/file/d/1lFYW26xsPGQp6WU9h6f2-E1bHW-hDIic/view?usp=sharing
const replaceKeys = obj => {
return Object.fromEntries(Object.entries(obj).map( ([key,value]) => {
return [
key.replace("-","_"),
Array.isArray(value)
? value.map(replaceKeys)
:typeof value == "object"
? replaceKeys(value)
: value
];
}))
}
const result = input.map(replaceKeys);
console.log(result);
You can do this transformation both, when you JSON.parse() the data from google, or when you JSON.stringify() the object to send it to big query.
imo. that's the most economical approach, to transform while parsing or serializing, instead of first parsing then transforming or first transforming then serializing.
// sources
const obj = {
"key-with-dashes": [{
"some-value": 42
}]
};
const json = JSON.stringify(obj);
// utilities
const includesDash = v => v.includes("-");
const replaceDashInKey = kv => {
kv[0] = kv[0].replace(/-/g, "_");
return kv;
}
const cleanupDashesInKeys = (k, v) => {
if (typeof v === "object" &&
v !== null &&
!Array.isArray(v) &&
Object.keys(v).some(includesDash)
) {
return Object.fromEntries(Object.entries(v).map(replaceDashInKey))
}
// this value has no keys with dashes
return v;
};
//cleanup keys
console.log("on parse", JSON.parse(json, cleanupDashesInKeys));
console.log("on stringify", JSON.stringify(obj, cleanupDashesInKeys));
.as-console-wrapper{top:0;max-height:100%!important}
I need to remove elements from a json string returned by an AJAX call.
I'm not sure how to loop through the string and remove all elements where the value i NULL.
My json looks like this.
[
{"ID":"27","Agility":"15","Balance":null,"Strength":"37","Physiology":"32"},
{"ID":"30","Agility":"27","Balance":null,"Strength":null,"Physiology":null},
{"ID":"34","Agility":null,"Balance":null,"Strength":null,"Physiology":null},
{"ID":"36","Agility":null,"Balance":null,"Strength":null,"Physiology":null},
{"ID":"40","Agility":null,"Balance":"20","Strength":null,"Physiology":"34"},
{"ID":"42","Agility":null,"Balance":"16","Strength":null,"Physiology":null},
{"ID":"51","Agility":null,"Balance":null,"Strength":"39","Physiology":null}
]
I thought I might do something like this for every key but i would prefer a generic function:
if(json[index].Strength == null){
json.splice(index,1);
}
You can parse json with JSON.parse method and then use filter() method on that array.
const json = '[{"ID":"27","Agility":"15","Balance":null,"Strength":"37","Physiology":"32"},{"ID":"30","Agility":"27","Balance":null,"Strength":null,"Physiology":null},{"ID":"34","Agility":null,"Balance":null,"Strength":null,"Physiology":null},{"ID":"36","Agility":null,"Balance":null,"Strength":null,"Physiology":null},{"ID":"40","Agility":null,"Balance":"20","Strength":null,"Physiology":"34"},{"ID":"42","Agility":null,"Balance":"16","Strength":null,"Physiology":null},{"ID":"51","Agility":null,"Balance":null,"Strength":"39","Physiology":null}]'
const data = JSON.parse(json).filter(o => o.Strength != null)
console.log(data)
If you want to remove elements where some property has value of null you can use some method inside filter.
const json = '[{"ID":"27","Agility":"15","Balance":null,"Strength":"37","Physiology":"32"},{"ID":"30","Agility":"27","Balance":null,"Strength":null,"Physiology":null},{"ID":"34","Agility":null,"Balance":null,"Strength":null,"Physiology":null},{"ID":"36","Agility":null,"Balance":null,"Strength":null,"Physiology":null},{"ID":"40","Agility":null,"Balance":"20","Strength":null,"Physiology":"34"},{"ID":"42","Agility":null,"Balance":"16","Strength":null,"Physiology":null},{"ID":"51","Agility":null,"Balance":null,"Strength":"39","Physiology":null}]'
const data = JSON.parse(json).filter(o => {
return !Object.keys(o).some(k => o[k] == null)
})
console.log(data)
Use filter:
const newJson = json.filter(item => item.Strength !== null)
If you prefer a generic function, Lodash is the best option.
PickBy picks up properties from an object, based on a Predicate.
Here predicate is Identity, which means, pickup non null properties from the object.
var jsonResponse = '[{"ID":"27","Agility":"15","Balance":null,"Strength":"37","Physiology":"32"},{"ID":"30","Agility":"27","Balance":null,"Strength":null,"Physiology":null},{"ID":"34","Agility":null,"Balance":null,"Strength":null,"Physiology":null},{"ID":"36","Agility":null,"Balance":null,"Strength":null,"Physiology":null},{"ID":"40","Agility":null,"Balance":"20","Strength":null,"Physiology":"34"},{"ID":"42","Agility":null,"Balance":"16","Strength":null,"Physiology":null},{"ID":"51","Agility":null,"Balance":null,"Strength":"39","Physiology":null}]';
var responseArr = JSON.parse(jsonResponse);
// Only lines that matter
responseArr = _.map(responseArr, function(obj) {
return _.pickBy(obj, _.identity);
});
console.log("Array of Objects: ", responseArr);
console.log("JSON: ", JSON.stringify(responseArr));
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.5/lodash.min.js"></script>
Put the above mentioned script tag just before closing tag of your html page.
So just loop through the whole array response using map, and apply PickBy on each object of the array, and you have yourself an array of sparse objects.
Try Array filter() method with ES6 Arrow function.
Demo
var jsonObj = [
{"ID":"27","Agility":"15","Balance":null,"Strength":"37","Physiology":"32"},
{"ID":"30","Agility":"27","Balance":null,"Strength":null,"Physiology":null},
{"ID":"34","Agility":null,"Balance":null,"Strength":null,"Physiology":null},
{"ID":"36","Agility":null,"Balance":null,"Strength":null,"Physiology":null},
{"ID":"40","Agility":null,"Balance":"20","Strength":null,"Physiology":"34"},
{"ID":"42","Agility":null,"Balance":"16","Strength":null,"Physiology":null},
{"ID":"51","Agility":null,"Balance":null,"Strength":"39","Physiology":null}
];
var res = jsonObj.filter(elem => elem.Strength !== null);
console.log(res);
I am looking for a short and efficient way to filter objects by key, I have this kind of data-structure:
{"Key1":[obj1,obj2,obj3], "Key2":[obj4,obj5,obj6]}
Now I want to filter by keys, for example by "Key1":
{"Key1":[obj1,obj2,obj3]}
var object = {"Key1":[1,2,3], "Key2":[4,5,6]};
var key1 = object["Key1"];
console.log(key1);
you can use the .filter js function for filter values inside an object
var keys = {"Key1":[obj1,obj2,obj3], "Key2":[obj4,obj5,obj6]};
var objectToFind;
var keyToSearch = keys.filter(function(objects) {
return objects === objectToFind
});
The keyToSearch is an array with all the objects filter by the objectToFind variable.
Remember, in the line return objects === objectToFind is where you have to should your statement. I hope it can help you.
You can create a new object based on some custom filter criteria by using a combination of Object.keys and the array .reduce method. Note this only works in es6:
var myObject = {"Key1":["a","b","c"], "Key2":["e","f","g"]}
function filterObjectByKey(obj, filterFunc) {
return Object.keys(obj).reduce((newObj, key) => {
if (filterFunc(key)) {
newObj[key] = obj[key];
}
return newObj;
}, {});
}
const filteredObj = filterObjectByKey(myObject, x => x === "Key1")
console.log(filteredObj)
Not sure what exactly are you trying to achieve, but if you want to have a set of keys that you would like to get the data for, you have quite a few options, one is:
var keys = ['alpha', 'bravo'];
var objectToFilterOn = {
alpha: 'a',
bravo: 'b',
charlie: 'c'
};
keys.forEach(function(key) {
console.log(objectToFilterOn[key]);
});
In the code below, I'm trying to search the JSON output for a specific string (for example 'name_col_lbl') and return its value (in this case 'Name') for AngularJS to ouptut in the view.
$scope.globalContent = [
{"id":"1","module":"student_reg","item":"name_col_lbl","value":"Name"},
{"id":"2","module":"student_reg","item":"bday_col_lbl","value":"Birthdate"}
]
angular.forEach($scope.globalContent, function(el){
$scope.nameLbl = el ***This is where I need to search for the string and return its value***;
$scope.bdayLbl= el ***This is where I need to search for the string and return its value***;
});
I can't seem to find an efficient way to handle this. Thanks in advance!
This should do the trick:
var $scopeglobalContent = [
{"id":"1","module":"student_reg","item":"name_col_lbl","value":"Name"},
{"id":"2","module":"student_reg","item":"bday_col_lbl","value":"Birthdate"}
];
for(var i = 0; i < $scopeglobalContent.length; i++){
for(key in $scopeglobalContent[i]){
if($scopeglobalContent[i][key] == "name_col_lbl"){
return console.log($scopeglobalContent[i].value);
}
}
}
This is basic stuff. I suggest you read on objects and loops to get a better understanding of how this works and how to use it.
From this stackoverflow answer, here's how you can search an array of objects:
var obj = array.filter(function ( obj ) {
return obj.item === "name_col_lbl";
});
obj will contain either the value of name_col_lbl or undefined if the key doesn't exist.
So your code would look like this:
function findObject(array, keyName) {
var obj = array.filter(function ( obj ) {
return obj.item === keyName;
})[0];
return obj;
}
$scope.globalContent = [
{"id":"1","module":"student_reg","item":"name_col_lbl","value":"Name"},
{"id":"2","module":"student_reg","item":"bday_col_lbl","value":"Birthdate"}
]
angular.forEach($scope.globalContent, function(el){
$scope.nameLbl = findObject($scope.globalContent, "name_col_lbl")['value]' ***This is where I need to search for the string and return its value***;
$scope.bdayLbl= findObject($scope.globalContent, "bday_col_lbl")['value]' ***This is where I need to search for the string and return its value***;
});
The findObject function filters the array by returning the first object that it finds where obj.item matches whatever is contained in keyName. This is the obj object which gets returned. Since you don't want the whole object but just a value of that object, I've taken the result of the findObject($scope.globalContent, "name_col_lbl") and added ['value'] which will return just the value key which is what you want to display in the Angular view.