Find and remove empty properties from objects - javascript

This is my array of objects:
var data = [
{
"label": "HOME",
"href": "web-tutor99.com",
"children": [{}]
},
{
"href": "web-tutor99.com",
"label": "HTML5"
}
];
It is a multidimensional object and here the children property is empty. How can I find empty properties like this and remove them using jQuery?

Try this
data = [{
"label": "HOME",
"href": "web-tutor99.com",
"children": [{}]
}, {
"href": "web-tutor99.com",
"label": "HTML5"
}];
alert("Before : "+JSON.stringify(data));
//console.log(data);
checkEmptyObj(data);
alert("After : "+JSON.stringify(data));
function checkEmptyObj(data) {
$.each(data, function(key, value) {
if ($.isPlainObject(value) || $.isArray(value)) {
checkEmptyObj(value);
}
//alert(key+":"+$.isEmptyObject(value));
if (value === "" || value === null || $.isEmptyObject(value)) {
delete data[key];
}
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

You could do this..
for (var i in data) {
if (test[i].children === null || test[i].children === undefined || test[i].children.length<=0) {
delete test[i].children;
}
}
But I see no practical use in wasting CPU cycles looping through objects to remove empty objects.
Not really sure what you're trying to achieve. But you're better off just checking if its empty, and then not displaying if its the case.

You could simply create a (if nested, recursive) function looping through all elements and check if the it has a value, if not, delete that property.
In your example object you have the problem that the children property is by far not empty - it is a property with a value of an array containing one empty object. Depending on your scenario you'd have to run through your object multiple times, removing empty entries step by step (could probably do some optimization).
As a final note, you can use for...in to loop through an object's properties and for...of to loop through an object's/array's values.

I think the following pure JS snippet takes care of the job. You can check it # JSBin
var data = [{"label":"HOME","href":"web-tutor99.com","children":[{}]},{"href":"web-tutor99.com","label":"HTML5"}];
function walkJSONObj(obj){
for (var prop in obj) {
if (obj[prop].constructor === Array) { //if prop is an array
walkJSONArray(obj[prop]); //go walk through the arrays
obj[prop].length === 0 && delete obj[prop]; //if on return the array is empty delete it
}
else typeof obj[prop] === 'undefined' && delete obj[prop]; //delete undefined props
}
}
function walkJSONArray(arr){
for (var l = arr.length-1; l >= 0; l--) {
walkJSONObj(arr[l]); // go walk the item objects
if (Object.keys(arr[l]).length === 0 && JSON.stringify(arr[l]) === JSON.stringify({})) {
arr.splice(l, 1); // if on return the object is empty delete it
}
}
}
walkJSONArray(data);

Related

How to search and replace key and value of nested object using javascript

I need to search and replace value from a nested object using javascript. I am explaining the object below.
let jsonObj = {
"service":[
{
"name":"restservice",
"device":"xr-1",
"interface-port":"0/0/2/3",
"interface-description":"uBot testing for NSO REST",
"addr":"10.10.1.3/24",
"mtu":1024
}
],
"person": {
"male": {
"name": "infinitbility"
},
"female": {
"name": "aguidehub",
"address": {
"city": "bbsr",
"pin": "752109"
}
}
}
}
In the above nested object I need to search the key and replace the value. Here my requirement is in the entire object it will search for the key name and where ever it is found it will replace the value as BBSR. In the above case there are 3 place where name key is present so I need to replace the value accordingly using Javascript.
You can try the deep search algorithm
Iterate over the entire object
Determine the current property
If the current property is object or array
then continue to recurse the property
If the property is not an object or array
then determine if the object's key == 'name'
if yes, then do what you want to do
If not, then do nothing
like this
const deepSearch = (target) => {
if (typeof target === 'object') {
for (let key in target) {
if (typeof target[key] === 'object') {
deepSearch(target[key]);
} else {
if (key === 'name') {
target[key] = 'xxx'
}
}
}
}
return target
}

Javascript Check Object for empty or null fields and arrays

I've got an array that has a lot of objects and embedded arrays. I need to iterate through the entire array to see if anything is empty or null. My problem is checking Arrays and whether or not the arrays return empty. I keep getting object arrays and they are not null or undefined so get added in even if length is 0. What I've got so far.
var progressCount = 0;
var progressKeyLength = progressBarCriteria.length;
for (var i = 0; i<progressKeyLength; i++){
//I can find the arrays here but still not able to check length since they are actually object arrays.
if(Array.isArray(progressBarCriteria[i])){
console.log('array' + i);
}
if (progressBarCriteria[i] !== null && progressBarCriteria[i] !== ""){
++progressCount
}
}
progressBarCritiria = [
example1: "",
example2: "asdasdas",
example3: 233,
example4: {asda: 1},
example5: {asadasda: "asdasdA"},
example6: "",
example7: [],
example8: [1, 12312],
example9: [{1: "ad"}, {1: 12312}],
]
So 1, 6 and 7 should not be added to my count.
If you need to check the length or null value for an array, you can think about the Truthy - Falsy value as follow:
if (Array.isArray(progressBarCriteria[i]) && progressBarCriteria[i].length) {
// This is an array and is not empty.
}
This Array.isArray(progressBarCriteria[i]) checks if that value is an array.
If this progressBarCriteria[i].length is 0 the boolean value will be false, ortherwise will be true.
You can use a recursive function to do that. It is important to notice that in javascript arrays are objects. So you need to check for objects by if (typeof arr === 'object' && !(arr instanceof Array)). For more informations check this and this.
function recursive_array_chekc (arr) {
//check if arr is an object
if (typeof arr === 'object' && !(arr instanceof Array)) {
//check if object empty
if (Object.keys (arr).length === 0) {
//do something if empty
console.log ('this object is empty');
} else {
//check object properties recursivly
for (var key in arr)
if (arr.hasOwnProperty (key))
recursive_array_chekc (arr[key])
}
} else
if (Array.isArray (arr)) {
//check if array is empty
if (arr.length === 0) {
//do something if empty
console.log ('this array is empty');
} else {
//check array elements recursivly
for (var i = 0; i < arr.length; i++)
recursive_array_chekc (arr[i])
}
}
}
I was able to look at both answers and came up with this working solution. This is using Typescript so sorry for confusion.
for (var i = 0; i<progressKeyLength; i++){
if (!(progressBarCriteria[i] instanceof Array)){
if(progressBarCriteria[i] !== null && progressBarCriteria[i] !== "") {
++progressCount
}
} else {
let current = progressBarCriteria[i];
if (Array.isArray(current) && current.length !== 0){
++progressCount
}
}
}

Looping though unique keys

I have a json object which I would like to loop through; however each object has a nested object which I can't access through dot notation due to the values being unique.
.__proto__
will give me consistent results; however I'd like to pull out the values starting with the "-Jg". Is it possible to do this through a regular expression or another method?
Edit:
I'm looping through the 'javascript object' with angular
var lognew = [];
angular.forEach(log, function(value, key) {
if(value){
if(value.substr(0,3) !== "-Jg" ){
this.push(value);
}
}
}, lognew);
console.log(lognew);
This currently returns:
TypeError: undefined is not a function
Just enumerate using for in and look at the first 3 characters of the object's key
for(var key in jsonObj){
if( key.substr(0,3) !== "-Jg" ) continue;
var nestedObject = jsonObj[key];
}
angular edit
var log = { "1": { "-Jga": "b" }, "2": { "-Jgc": "d" } };
var lognew = [];
angular.forEach(log, function(value, key) {
if(key){
if(key.substr(0,3) !== "-Jg" ){
this.push(value);
}
}
}, lognew);
console.log(lognew);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

JSON get a value if another value

Okay so my JSON is something along the lines of:
{
"wares":[
{
"id":"1",
"name":"apples",
"stock":"40",
},
{
"id":"2",
"name":"pears",
"stock":"40",
},
{
"id":"3",
"name":"bananas",
"stock":"30",
}
]
}
So I would like to get the name if the stock is 40, I've used this code as an example, which I found here: http://techslides.com/how-to-parse-and-search-json-in-javascript/
function getObjects(obj, key, val) {
var objects = [];
for (var i in obj) {
if (!obj.hasOwnProperty(i)) continue;
if (typeof obj[i] == 'object') {
objects = objects.concat(getObjects(obj[i], key, val));
} else
//if key matches and value matches or if key matches and value is not passed (eliminating the case where key matches but passed value does not)
if (i == key && obj[i] == val || i == key && val == '') { //
objects.push(obj);
} else if (obj[i] == val && key == ''){
//only add if the object is not already in the array
if (objects.lastIndexOf(obj) == -1){
objects.push(obj);
}
}
}
return objects;
}
which works, but I haven't quite found a way to return the name if the stock is 40.
I was thinking you put an extra value in the function called ret (return) as in what it should return. Something along the lines of
alert(JSON.stringify(getObjects(JSON, 'stock', '40', 'name')));
Thanks a lot!
An alternate solution using the native filter() and map() methods:
function getObjects(_object, _key, _value, _return) {
return _object.filter(function(_item) {
return _item[_key] == _value;
}).map(function(_item) {
return _item[_return];
});
}
Note that in the above call, we need to pass the array containing the items, not the root object. Or you can modify the above to accept the root object
And you call it like:
getObjects(obj.wares, 'stock', 40, 'name');
to get back ["apples", "pears"]
Try this out!
$.each(getObjects(JSON, "stock", "40"), function() {
alert(this.name);
})
EDIT: Just in order to explain what I wrote, the getObjects function returns all the objects that matches the search criteria, so then what I did was to get each name of all the JSONS that are returned

Get array of key-values from array of objects without knowing format of array of objects (Javascript)?

Imagine I'm given a reference to an array of similar objects, e.g. array will be the name of that array. Now I'm asked to create an array of all the values of some property that is found inside each object of that array, e.g. "user.id".
The problem is that I won't know the format of each object and where that property will reside/be nested.So "user.id" might reside in array[#].someKey (array[#].someKey["user.id"])or in array[#].someKey.someOtherKey (array[#].someKey.someOtherKey["user.id"])
Is there a function (jQuery, underscore..etc) that could create such an array ?
e.g. var arrayOfUserIds = returnArray(array, "user.id");
For example, imagine that the following is an example of such an array :
var array = [
{
"age": "13",
"type": "publish_action",
"tag": null,
"timestamp": 1398931707000,
"content": {
"action": "publish",
"user.id": "860",
"user.email": "alex#somemail.com",
"property.id": "2149",
"iteration_id": "15427",
"test_id": "6063",
"property.name" : "bloop"
}, {
....
}, {
....
}];
Based on the above, I could obviously do :
var arrayOfUserIds = [];
for (var i=0; i<array.length; i++)
{
arrayOfUserIds.push(array[i]["content"]["user.id"]);
}
But like I said, in my case I won't know about the format of the object so I can't create such a for-loop for example.
Any ideas will be much appreciated!
Thank you!
If I understand correctly, each object in someArray either contains a property user.id or an object that contains user.id...or, recursively, some object that contains someArray. You want to create an array containing only the user.id properties.
An easy way to do this would be to do a recursive examination of each object in the array until user.id is located:
// get `user.id` property from an object, or sub-object
// it is assumed that there will only be one such property;
// if there are more than one, only the first one will be returned
function getUserId(o){
if(o===null || o===undefined) return;
if(o['user.id']) return o['user.id'];
for(var p in o){
if(!o.hasOwnProperty(p)) continue;
if(typeof o[p] !== 'object') continue;
if(o[p] === null || o[p] === undefined) continue;
var id = getUserId(o[p]);
if(id) return id;
}
}
function getUserIds(arr){
return arr.map(function(e){
return getUserId(e);
});
}
If you want something a little more generic, you could write a "find" method that will find all instances of a named property in an object tree:
var find = (function(){
function find(matches, o, prop, checkPrototypeChain){
if(typeof o[prop] !== 'undefined') matches.push(o[prop]);
for(var p in o){
if(checkPrototypeChain || !o.hasOwnProperty(p)) continue;
if(typeof o[p] !== 'object') continue;
if(o[p] === null || o[p] === undefined) continue;
find(matches, o[p], prop, checkPrototypeChain);
}
}
return function(o, prop, checkPrototypeChain){
var matches = [];
find(matches, o, prop, checkPrototypeChain);
return matches;
}
})();
Then you could just map your array based on that:
var userIds = someArray.map(function(e){ return find(e, 'user.id'); });
Note that I'm glossing over properties that may be in the prototype chain, but in the find function, I added the ability to additionally search for properties in the prototype chain.
I went with the assumption that you're only working with primitives and object/array literals. In which case, the following method (using underscore) seems to do the trick.
var testSubject = {
mykey: 9,
firstArray: [
{something: 9, another: {x: 'hello', mykey: 'dude'}, mykey: 'whatever'},
{something: 9, another: {x: 'hello', mykey: 'dude2'}, mykey: 'whatever2'},
{
someArray: [
{seven: 7, mykey: 'another'},
{hasNo: 'mykey', atAll: 'mykey'}
]
}
],
anObject: {beef: 'jerky', mykey: 19}
};
function getValuesForKey(subject, searchKey) {
return _.reduce(subject, function(memo, value, key) {
if (_.isObject(value)) {
memo = memo.concat(getValuesForKey(value, searchKey));
} else if (key === searchKey) {
memo.push(value);
}
return memo;
}, []);
}
console.log(getValuesForKey(testSubject, 'mykey'));
// -> [9, "dude", "whatever", "dude2", "whatever2", "another", 19]
It only returns the list of values because they will all share the same key (i.e. the one specified). Additionally, I do believe any matching keys will be ignored if their values are not primitive (e.g. mykey: {…} or mykey: […] should be ignored). I hope it helps.

Categories

Resources