Reputation: 1242
I got an object which looks like this :
{
"a": "string not empty",
"b": {
"c": "string not empty",
},
"d": {
"e": false,
"f": 0,
"g": true,
"h": 10
},
"i": {
"j": 0,
"k": null
},
"l": {
"m": null
},
"n": {
"o": 1,
"p": "string (not empty)",
"q": {}
},
"r": [],
"l": "2000-01-01T01:01:00.000Z",
}
Thanks to the code provided by here : https://stackoverflow.com/a/38364486/3912805 I can now remove all null
values of my nested object.
I used this function so far to removeNull
:
removeNull = (obj) => {
Object.keys(obj).forEach(key =>
(obj[key] && typeof obj[key] === 'object') && removeNull(obj[key]) ||
(obj[key] === undefined || obj[key] === null) && delete obj[key]
);
return obj;
};
But I would like to enhance this function to allow me to remove all empty arrays or any empty collection which may exists in my nested object.
Final results should be without k
, l
& m
, q
, r
, l
:
{
"a": "string not empty",
"b": {
"c": "string not empty",
},
"d": {
"e": false,
"f": 0,
"g": true,
"h": 10
},
"i": {
"j": 0
},
"n": {
"o": 1,
"p": "string (not empty)"
},
"l": "2000-01-01T01:01:00.000Z",
}
I need to keep all values which were set to 0
or to false
.
I would like to enhance this removeNull
's method using ES6 method, but so far I failed to do it.
I also tried old school method which was used for this How to deeply remove null values, empty objects and empty array from an object
itemToBool = item => {
if (typeof item !== 'object' || item === null) return item;
const cleanedItem = cleanObject(item);
return Object.keys(cleanedItem).length !== 0 && cleanedItem;
};
cleanObject = obj => {
if (Array.isArray(obj)) {
const newArr = obj.map(itemToBool).filter(Boolean);
return newArr.length && newArr;
}
const newObj = Object.entries(obj).reduce((a, [key, val]) => {
const newVal = itemToBool(val);
if (newVal !== null || newVal === false) a[key] = newVal;
return a;
}, {});
return Object.keys(newObj).length > 0 && newObj;
};
but it fails too.
Upvotes: 15
Views: 22187
Reputation: 551
you can try this
var testvar = {
test1: null,
test2: 'string',
test3: 3,
}
function removenull(obj) {
for (var propName in obj) {
if (obj[propName] === null || obj[propName] === undefined) {
delete obj[propName];
}
}
return obj
}
console.log(testvar);
console.log(removenull(testvar));
Upvotes: 0
Reputation: 1
// remove all falsy attributes for all layers of object
const removeFalsyProps = (body) => {
let data = body;
Object.keys(data).forEach((key) => {
let value = data[key];
// trim string type value
if (typeof value == 'string') {
value = value.trim();
}
// check value is falsy or not, then delete the property
if (!value) {
delete data[key];
}
// check value is object or not, If object then recursively call. (In JS null and array is object type)
if (typeof value == 'object' && value != null && !Array.isArray(value)) {
removeFalsyProps(value);
}
});
return data;
};
const myOb = {
a: 2,
y: undefined,
x: 0,
s: null,
b: ' ',
c: { d: 8, i: '', j: { k: 1, l: '', m: { o: null, p: 'seven' } } },
e: 'test',
h: { a: '', b: 8, c: { d: 'de', e: 0 } },
i: { array: ['hello'], bc: '' },
j: 45,
array: [],
};
console.log(removeFalsyProps(myOb));
Upvotes: 0
Reputation: 3663
have just solved the same issue, so I want to share with you guys. My code also clean nested object and array, can be customize depend on your requirement :
cleanObject = (input) => {
if (typeof input === 'object' && input !== null) {
if(Array.isArray(input)) {
return input.map(cleanObject)
.filter(item => item !== null && item !== undefined)
}
return Object.fromEntries(
Object.entries(input)
.map(([key, val]) => [key, cleanObject(val)])
.filter(([k, v]) => v !== null && v !== undefined)
);
}
return input;
}
// testcase:
const testVal = {
a: 1,
b: 2,
c: undefined,
d: { a: 99, b: null },
e: { a: 1, b: 2, d: undefined, g: null, e: 0 },
f: [1, 0, null, undefined],
g: [1, 2],
h: { aa: 1, bb: { c: 1, d: [111, null], e: 'hello' } },
};
cleanObject(testVal);
Upvotes: 1
Reputation: 416
function cleanObject(obj: object) {
// remove all keys with undefined values in nested objects
const cleaned = Object.entries(obj).reduce((acc, [key, val]) => {
if (val && typeof val === 'object') {
val = cleanObject(val);
}
if (val !== undefined) {
acc[key] = val;
}
return acc;
}, {});
return cleaned;
}
const data = {
a: 50,
b: 90,
c: undefined,
d: undefined,
e: {
a: 90,
b: 80,
c: undefined,
d: undefined,
},
f: {
a: undefined,
b: undefined,
c: undefined,
d: undefined,
},
};
console.log(cleanObject(data));
output => { a: 50, b: 90, e: { a: 90, b: 80 }, f: {} }
Upvotes: 0
Reputation: 31
To remove empty arrays, strings, null, undefined values
function removeEmptyElements(obj) {
if (Array.isArray(obj)) {
obj.forEach((element, index) => obj.splice(index, 1, removeEmptyElements(element)));
return obj;
}
return Object.fromEntries(Object.entries(obj)
.filter(([, v]) => (Array.isArray(v) ? v.length !== 0 : (v !== null && v !== '' && v !== undefined)))
.map(([k, v]) => [k, v === (Object(v)) ? removeEmptyElements(v) : v]));
}
Upvotes: 3
Reputation: 2348
I tried it by as follow
const test = {
a: '',
b: 1,
c: [],
d: {
e: null,
f: 0,
g: undefined,
h: {
i: 'test',
j: {},
k: '',
l: {
m: 'yo test',
n: 'go for it'
}
}
},
e: 'yo tested'
};
const JS_PRIMITIVE_TYPES = { 'string': 1, 'number': 1, 'undefined': 1, 'boolean': 1,
'symbol': 1 }
const isValuePrimitiveType = (value) => {
const typeOfVal = typeof value;
if (JS_PRIMITIVE_TYPES.hasOwnProperty(typeOfVal)) {
return true;
}
return false;
}
/* MAIN Function which runs and call other functions
allKeys : keys of object Object.keys(test);
badJson : json which needs to be update
*/
const iterateObjForRemoveEmptyElem = (badJson, allKeys) => {
for (let index = 0; index < allKeys.length; index++) {
const key = allKeys[index];
if (isEmpty(badJson[key])) {
delete badJson[key];
} else if (Array.isArray(badJson[key]) || isValuePrimitiveType(badJson[key])) {
continue;
}
else {
const newKeys = Object.keys(badJson[key]);
const newJson = Object.assign({}, badJson[key]);
badJson[key] = iterateObjForRemoveEmptyElem(newJson, newKeys);
}
}
return badJson;
}
const isEmpty = (val) => {
if(val === '' || val === null || val === undefined ) {
return true;
} else if (Array.isArray(val) && val.length === 0){
return true;
} else if(typeof val === 'object' && Object.keys(val).length === 0){
return true;
}
return false;
}
const myKeys = Object.keys(test);
console.log("Final Result:::::",JSON.stringify(iterateObjForRemoveEmptyElem(test,myKeys)));
This works for me upto nth level
Upvotes: 0
Reputation: 171
//sample Json Response
var items = {
name: 'test',
randomArray: [],
randomObject: {
id: null,
someObject: {},
someInternalArray: [],
someUndefinedObject: undefined,
},
New name: null,
nestedObject: [
{
emp: {
id: null,
},
empAssets: 2,
joiningDate: {
startDate: null,
endDate: '2019/12/01',
Addresses: [],
},
},
],
};
this.removeEmptyKeys(items);
console.log('the final items ‘,items);
//Removing logic
removeEmptyKeys(yourObject) {
Object.keys(yourObject).forEach(key => {
if (
Object.prototype.toString.call(yourObject[key]) === '[object Date]' &&
(yourObject[key].toString().length === 0 ||
yourObject[key].toString() === 'Invalid Date')
) {
delete yourObject[key];
} else if (yourObject[key] && typeof yourObject[key] === 'object') {
this.removeEmptyKeysFromObject(yourObject[key]);
} else if (yourObject[key] == null || yourObject[key] === '') {
delete yourObject[key];
}
if (
yourObject[key] &&
typeof yourObject[key] === 'object' &&
Object.keys(yourObject[key]).length === 0 &&
Object.prototype.toString.call(yourObject[key]) !== '[object Date]'
) {
delete yourObject[key];
}
});
return yourObject;
}
Remove undefined, null, empty string , empty Arrays. Upvote if it helps.
Upvotes: -2
Reputation: 4137
You can exploit JSON.stringify
and it's optional second argument replacer
but be aware the following code removes null
and undefined
.
const sanitize = (obj) => {
return JSON.parse(JSON.stringify(obj, (key, value) => {
return (value === null ? undefined : value);
}));
};
const obj = {
"a": "string not empty",
"b": {
"c": "string not empty",
},
"d": {
"e": false,
"f": 0,
"g": true,
"h": 10
},
"i": {
"j": 0,
"k": null
},
"l": {
"m": null
},
"n": {
"o": 1,
"p": "string (not empty)",
"q": {}
},
"r": [],
"l": "2000-01-01T01:01:00.000Z",
}
console.log(sanitize(obj))
Upvotes: 14
Reputation: 1242
Thanks to Nina Scholz, my enhanced version will be :
cleanObject = function(object) {
Object
.entries(object)
.forEach(([k, v]) => {
if (v && typeof v === 'object')
cleanObject(v);
if (v &&
typeof v === 'object' &&
!Object.keys(v).length ||
v === null ||
v === undefined ||
v.length === 0
) {
if (Array.isArray(object))
object.splice(k, 1);
else if (!(v instanceof Date))
delete object[k];
}
});
return object;
}
Upvotes: 9
Reputation: 4175
If you don't want to mutate the object and need a new copy, then you can stringify the object to json and parse it, and filter at the time of parsing. If you don't need the source object then you can override the result into same reference. Its may not the performance efficient approach but obviously much cleaner and not a self recursive approach.
var obj = {
"a": "string not empty",
"b": {
"c": "string not empty",
},
"d": {
"e": false,
"f": 0,
"g": true,
"h": 10
},
"i": {
"j": 0,
"k": null
},
"l": {
"m": null
},
"n": {
"o": 1,
"p": "string (not empty)",
"q": {}
},
"r": [],
"s": {"t": null},
"u": [null, {"v": {}}]
}
function copyNonEmpty(o) {
let ignores = [null, undefined, ""],
isNonEmpty = d => !ignores.includes(d) && (typeof(d) !== "object" || Object.keys(d).length)
return JSON.parse(JSON.stringify(o), function(k, v) {
if (isNonEmpty(v))
return v;
});
}
var res = copyNonEmpty(obj);
console.log(JSON.stringify(res, null, 4));
If value is Object
or Array
then typeof
will return object
and Object.keys
will return a array of keys for both the cases ("0", "1"
,2
... in case of array), and the array length (of keys) will 0 if its an empty array or object. So, conditionally, it will must not (null
, undefined
or ""
) and (either a non object/array
OR object/array
which is non-empty and then you can take that value.
Upvotes: 3
Reputation: 386560
You could take an straight forward approach by iterating the key/value pairs of the object and iterate nested iterable objects first and then delete the unwanted keys.
function clean(object) {
Object
.entries(object)
.forEach(([k, v]) => {
if (v && typeof v === 'object') {
clean(v);
}
if (v && typeof v === 'object' && !Object.keys(v).length || v === null || v === undefined) {
if (Array.isArray(object)) {
object.splice(k, 1);
} else {
delete object[k];
}
}
});
return object;
}
var object = { a: "string not empty", b: { c: "string not empty" }, d: { e: false, f: 0, g: true, h: 10 }, i: { j: 0, k: null }, l: { m: null }, n: { o: 1, p: "string (not empty)", q: {} }, r: [{ foo: null }] };
console.log(clean(object));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 15