29

I have a JSON obj, after some operations (like delete some pieces), I print it and everything looks good except that I have some null values. How do I remove these?

I use JSON.stringify(obj, null, 2) method to print, and here is what it looks like:

{
    "store": {
        "book": [
             null,
             {
                 "category": "fiction",
                 "author": "Evelyn Waugh",
                 "title": "Sword of Honour",
                 "price": 12.99
             },
             null,
             {
                  "category": "fiction",
                  "author": "J. R. R. Tolkien",
                  "title": "The Lord of the Rings",
                  "isbn": "0-395-19395-8",
                  "price": 22.99
             }
        ],
        "bicycle": {
             "color": "red",
             null,
             "price": 19.95
        }
    }
}

I want it to be much compact and pretty clean(remove the extra 3 null values):

{
    "store": {
        "book": [
             {
                 "category": "fiction",
                 "author": "Evelyn Waugh",
                 "title": "Sword of Honour",
                 "price": 12.99
             },
             {
                  "category": "fiction",
                  "author": "J. R. R. Tolkien",
                  "title": "The Lord of the Rings",
                  "isbn": "0-395-19395-8",
                  "price": 22.99
             }
        ],
        "bicycle": {
             "color": "red",
             "price": 19.95
        }
    }
}
4
  • 5
    Your bicycle is not valid syntax because of the null. Commented Aug 29, 2013 at 15:38
  • 1
    I wonder which implementation of JSON.stringify generated that invalid JSON. Commented Aug 29, 2013 at 15:47
  • ignore the bicycle element, you are right here, and it's my mistake Commented Aug 29, 2013 at 16:11
  • This is not a duplicate, due to the recursive aspect. Commented Aug 29, 2013 at 16:28

8 Answers 8

54

I had to solve a similar problem, however I wanted to remove not only null values but also undefined, NaN, empty String, empty array and empty object values, recursively, by inspecting nested objects and also nested arrays.

The following function is using Lo-Dash:

function pruneEmpty(obj) {
  return function prune(current) {
    _.forOwn(current, function (value, key) {
      if (_.isUndefined(value) || _.isNull(value) || _.isNaN(value) ||
        (_.isString(value) && _.isEmpty(value)) ||
        (_.isObject(value) && _.isEmpty(prune(value)))) {

        delete current[key];
      }
    });
    // remove any leftover undefined values from the delete 
    // operation on an array
    if (_.isArray(current)) _.pull(current, undefined);

    return current;

  }(_.cloneDeep(obj));  // Do not modify the original object, create a clone instead
}

For example, if you invoke the method with the following input object:

var dirty = {
  key1: 'AAA',
  key2: {
    key21: 'BBB'
  },
  key3: {
    key31: true,
    key32: false
  },
  key4: {
    key41: undefined,
    key42: null,
    key43: [],
    key44: {},
    key45: {
      key451: NaN,
      key452: {
        key4521: {}
      },
      key453: [ {foo: {}, bar:''}, NaN, null, undefined ]
    },
    key46: ''
  },
  key5: {
    key51: 1,
    key52: '  ',
    key53: [1, '2', {}, []],
    key54: [{ foo: { bar: true, baz: null }}, { foo: { bar: '', baz: 0 }}]
  },
  key6: function () {}
};

It'll recursively discard all the "bad" values, keeping in the end only the ones that carry some information.

var clean = pruneEmpty(dirty);
console.log(JSON.stringify(clean, null, 2));

{
  key1: 'AAA',
  key2: {
    key21: 'BBB'
  },
  key3: {
    key31: true,
    key32: false
  },
  key5: {
    key51: 1,
    key52: '  ',
    key53: [1, '2'],
    key54: [{ foo: { bar: true }}, { foo: { baz: 0 }}]
  }
};

Hope it helps!

Sign up to request clarification or add additional context in comments.

4 Comments

One of the best answers...(y)
Nice! However, this seems to be filtering out dates, which is probably not what we want. Should we check for !_.isDate(value) as well, before we delete current[key]?
Alternatively, we might make use of _.isPlainObject(value), we would need to handle arrays more explicitly in that case.
this is so much shorter than my brute force non-recursive method. i also added a condition to remove false values for example i just added 2 more conditions in the .forOwn if statement ( if value === false || value === 'false' || ...... ty!
18
// Iterate the array from back to front, removing null entries
for (var i=obj.store.book.length;i--;){
  if (obj.store.book[i]===null) obj.store.book.splice(i,1);
}

If you want to remove all null values recursively from both objects and arrays:

// Compact arrays with null entries; delete keys from objects with null value
function removeNulls(obj){
  var isArray = obj instanceof Array;
  for (var k in obj){
    if (obj[k]===null) isArray ? obj.splice(k,1) : delete obj[k];
    else if (typeof obj[k]=="object") removeNulls(obj[k]);
  }
}

Seen in action:

var o = {
  "store": {
    "book": [
       null,
       {
         "category": "fiction",
         "author": "Evelyn Waugh",
         "title": "Sword of Honour",
         "price": 12.99
       },
       null,
       {
          "category": "fiction",
          "author": "J. R. R. Tolkien",
          "title": "The Lord of the Rings",
          "isbn": "0-395-19395-8",
          "price": 22.99
       }
    ],
    "bicycle": {
       "color": "red",
       "bad": null,
       "price": 19.95
    }
  }
}

removeNulls(o);

console.log(JSON.stringify(o,null,2));
// {
//   "store": {
//     "book": [
//       {
//         "category": "fiction",
//         "author": "Evelyn Waugh",
//         "title": "Sword of Honour",
//         "price": 12.99
//       },
//       {
//         "category": "fiction",
//         "author": "J. R. R. Tolkien",
//         "title": "The Lord of the Rings",
//         "isbn": "0-395-19395-8",
//         "price": 22.99
//       }
//     ],
//     "bicycle": {
//       "color": "red",
//       "price": 19.95
//     }
//   }
// }

12 Comments

how to recursively iterate a object to apply this routine? consider i have no idea of the structure of the object, the store.book is just a example i wrote here.. i'm a new Javascript guy totally
I've added an implementation that will recursively crawl objects/arrays and remove null values.
thanks, don't know why it never fall into this 'if' branch: if (obj[k]===null), hm..
Great example! The only problem for me was that .splice() removes the current index and therefore skips the one right after it. Therefore i modified it to: for (var i = Object.keys(obj).length; i > 0; i--){ var key = Object.keys(obj)[i]; if(obj[key] === null ) { obj.splice(key,1); } else if (typeof obj[key]=="object") { this.cleanArray(obj[key]); } } return obj; With this modification the list also deletes items right after each other var o = { "store": { "book": [ null, null, null]}};
The second code snippet is incorrect and will fail on for example removeNulls([1,2,3,null,null,4,5]) and return [1,2,3,null,4,5] instead of removing both nulls.
|
12

We can use JSON.stringify and JSON.parse together to recursively remove blank attributes from an object.

jsObject = JSON.parse(JSON.stringify(jsObject), (key, value) => {
               if (value == null || value == '' || value == [] || value == {})
                   return undefined;
               return value;
           });

Comments

4

Fixing your book array is easy enough - you just have to filter out the nulls. The most straightforward way would probably be building a new array and reassigning it:

var temp = [];
var i;
for (i = 0; i < obj.store.book.length; ++i) {
    if (obj.store.book[i] != null) {
        temp.push(obj.store.book[i]);
    }
}
obj.store.book = temp;

I'm sure there are plenty of other ways, like using jQuery, or the filter function (which I believe is not available in older browsers). You could also loop through the array and splice out the nulls. I just find this way the easiest to read.

Comments

4

The following is a modification to the answer by @Phrogz. If book[3] was also null, the answer given would not remove the last null because the array's length would be less than k in last loop's iteration.

The following would work by performing a second call to the array:

function removeNulls(obj) {
  var isArray = obj instanceof Array;
  for (var k in obj) {
    if (obj[k] === null) isArray ? obj.splice(k, 1) : delete obj[k];
    else if (typeof obj[k] == "object") removeNulls(obj[k]);
    if (isArray && obj.length == k) removeNulls(obj);
  }
  return obj;
}

Comments

3

Please use this npm package

npm i --save nnjson
var nnjson = require('nnjson');
user = {
  a: null,
  b: 'hello',
  c: {
    c1: 'world',
    c2: null
  }
}
var newUser = nnjson.removeNull(user);
console.log (newUser)

result

{
  b: 'hello',
  c: {
    c1: 'world'
  }
}

Comments

1

How do you deletes your pieces ?

Delete an array element with the delete operator leaves a hole in the array. Instead, you should use Array.splice which can remove properly an element from array.

Comments

0

I use the code here

Remove empty elements from an array in Javascript

then you could call it like

JSON.stringify(obj.clean(null), null, 2)

You would need to modify the code to work with objects too (or use the code as is inside the objects)

1 Comment

Yes, Thats why i said either modify or run it inside the objects

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.