lauxp
lauxp

Reputation: 291

Recursively remove null values from JavaScript object

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
        }
    }
}

Upvotes: 29

Views: 37519

Answers (8)

Vardaman PK
Vardaman PK

Reputation: 323

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;
           });

Upvotes: 12

Nomura Nori
Nomura Nori

Reputation: 5167

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'
  }
}

Upvotes: 3

cortopy
cortopy

Reputation: 2867

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;
}

Upvotes: 4

jgonian
jgonian

Reputation: 2081

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!

Upvotes: 54

Phrogz
Phrogz

Reputation: 303224

// 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
//     }
//   }
// }

Upvotes: 18

BAK
BAK

Reputation: 1015

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.

Upvotes: 1

exussum
exussum

Reputation: 18550

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)

Upvotes: 0

Joe Enos
Joe Enos

Reputation: 40393

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.

Upvotes: 4

Related Questions