2

So I am given a json and I have to clean it up, by removing all the 'blank' fields. The fields that are considered blank are:

  • empty arrays or objects,
  • strings with whitespace ("" or " "),
  • null values.

This is what I have so far:

const isBlank = (val) => {
    if(val === null ) {
        return true
    }
    if(typeof val === 'string'){
        return val.trim().length === 0;
    }
    return val.length === 0
};


function clean(jsonInput) {
    Object.keys(jsonInput).forEach( key => {
        if(typeof jsonInput[key] === 'object' && !isEmpty(jsonInput[key])){
            clean(jsonInput[key])
        }else {
            isEmpty(jsonInput[key_field]) && delete jsonInput[key]
        }
    })

}

This is the jsonInput I am working with:

{
    "print": "notBlank",
    "this": "notBlank",
    "example": "notBlank",
    "blank": null,
    "allBlanks": [
        {
            "from": "",
            "blank0": null
        }
    ],
    "att2": {
        "blank1": "",
        "blank2": []
    },
    "att3": {
        "one": "1",
        "two": "2",
        "three": "3",
        "blank3": " "
    }
}

This should be the output:

{
    "print": "notBlank",
    "this": "notBlank",
    "example": "notBlank",
    "att3": {
        "one": "1",
        "two": "2",
        "three": "3"
    }
}

Instead I am getting this:

{
    "print": "notBlank",
    "this": "notBlank",
    "example": "notBlank",
    "allBlanks": [{ }],
    "att2": {},
    "att3": {
        "one": "1",
        "two": "2",
        "three": "3",
    }
}

It seams like I am unable to remove the objects... Any ideas what I am doing wrong? Any way I can fix it.

Also is there a way to do this so that I don't change the original object and instead I make a duplicate, maybe with map or filter?

Travis J
  • 81,153
  • 41
  • 202
  • 273
lokilindo
  • 682
  • 5
  • 17
  • 1
    This question has nothing to do with JSON. Parse the JSON, then deal with the resulting objects. Yes, `filter` is generally what you want, and it looks like you want to do this recursively but it isn't entirely clear. – Brad May 21 '18 at 21:26

2 Answers2

3

The main issue here is that [{}] was not defined as "empty" because it was an array of length 1 with an object in it. However, because you would like empty objects to be considered empty, and thus arrays with empty objects to be empty, you need to also recurse inside of your isEmpty function to cover these angles.

Note the two recursive calls for arrays and objects added to isEmpty.

As for as copying goes, the quick dirty way would be to first stringify then parse the json. You can see this towards the bottom of the code with the line

var jsonCopy = JSON.parse(JSON.stringify(json));

There are more complex ways of deep copying as well, please read What is the most efficient way to deep clone an object in JavaScript? for more information there.

const isEmpty = (val) => {
    if(val === null ) {
        return true
    }
    if(typeof val === 'string'){
        return val.trim().length === 0;
    }
    if(val instanceof Array){
        if( val.length === 0 ) return true;
        return val.every( v => 
          isEmpty(v)
        );
    }
    if(val === Object(val)){
        if(Object.keys(val).length == 0) return true;
        return Object.values(val).every( 
            v => isEmpty(v)
        );
    }
    return val.length === 0;
};


function clean(jsonInput) {
    Object.keys(jsonInput).forEach( key =>     {
        if(typeof jsonInput[key] === 'object' && !isEmpty(jsonInput[key])){
            clean(jsonInput[key])
        }else {
            isEmpty(jsonInput[key]) && delete jsonInput[key]
        }
    })
}

var json = {
    "print": "notBlank",
    "this": "notBlank",
    "example": "notBlank",
    "blank": null,
    "allBlanks": [
        {
            "from": "",
            "blank0": null
        }
    ],
    "att2": {
        "blank1": "",
        "blank2": []
    },
    "att3": {
        "one": "1",
        "two": "2",
        "three": "3",
        "blank3": " "
    }
};
var jsonCopy = JSON.parse(JSON.stringify(json));
clean(jsonCopy);
console.log(jsonCopy);
Travis J
  • 81,153
  • 41
  • 202
  • 273
0

Some features like this already exist in the lodash

https://lodash.com/docs/4.17.10#omitBy

Avoid using delete in javascript, its slow and not a good pratice

Example:

var _ = require("lodash")

var oldObj = {a:1, b:2, c:null, d:"aa"}

var newObj = _.omitBy(oldObj, (value, key) => 
                              _.isNull(value) || 
                              (_.isString(value) && _.isEmpty(value)) ||
                              (_.isArray(value) && _.isEmpty(value))  );
console.log("Final", newObj) //Final { a: 1, b: 2, d: 'aa' }

isEmpty return true if value is a number https://lodash.com/docs/4.17.10#isEmpty

Edit:

The keyword delete throws an exception in strict mode https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete