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.
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; }
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))
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;
}
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.
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]));
}
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);
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));
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
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: {} }
// 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));
//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.
Related
I want to be able to sort the nested object below from the lowest number to the high number...
{
"a": 50,
"b": {
"c": {
"d": 69,
"e": 420,
"f": 21,
"g": {
"h": 5,
"i": 3,
}
}
},
"j": 1,
"k": 1000
}
... so that it can look like this:
{
"j": 1, // min in OBJECT
"b": {
"c": { // min in B
"g": { // min in C
"i": 3, // min in G
"h": 5
},
"f": 21,
"d": 69,
"e": 420
}
},
"a": 50,
"k": 1000
}
Note that the object is sorted by the lowest number inside objects, meaning the object's direct children's values are [1, 3, 50, 1000].
Quick and dirty using Object.entries, Array forEach, Array reduce and Array sort
getpaths creates an array in the form
[
["a.b.c", 2],
["d.e", 1],
....
]
not really happy with the code for getpaths - if someone has better code, please let me know
Which can then be sorted easily using Array sort
createPath takes a root object, a path and a value and creates the "path" in the object
so, given {}, "a.b.c", 2
would result in
{
a: {
b: {
c: 2
}
}
}
Since (non numeric) object keys are "sorted" in insertion order [ref], inserting the values in value order produces the object as required
let obj = { a: 50, b: { c: { d: 69, e: 420, f: 21, g: { h: 5, i: 3, }, }, }, j: 1, k: 1000 };
const getpaths = (obj) => {
const paths = [];
const fn = (obj, path = "") => {
Object.entries(obj).forEach(([key, value]) => {
if (typeof value === "object") {
return fn(value, `${path}.${key}`);
}
paths.push([`${path}.${key}`.slice(1), value]);
});
};
fn(obj);
return paths;
};
const createPath = (obj, [path, value]) => {
path.split(".").reduce(
(acc, key, index, array) => acc[key] ||= array[index + 1] ? {} : value, obj);
return obj;
};
const result = getpaths(obj)
.sort(([, a], [, b]) => a - b)
.reduce((acc, item) => createPath(acc, item), {});
console.log(JSON.stringify(result, null, 4));
This question already has answers here:
One liner to flatten nested object
(19 answers)
Closed 1 year ago.
I am trying to achieve it Like a:1,b:2:,c:3,e:4,g:5,h:6
But not getting success.
Facing error this. But is the best way to do it.
const input = {
a: 1,
b: 2,
c: 3,
d: {
e: 4,
f: {
g: 5,
h: 6
}
}
}
const getValue = (values) => {
for (let i in Object.keys(values)) {
if (Object.keys(values[Object.keys(values)[i]]).length > 0) {
console.log('v', Object.keys(values)[i])
getValue(Object.keys(values)[i])
} else {
// console.log(Object.keys(values)[i],Object.values(values)[i])
}
}
}
getValue(input)
You can iterate through each key of object and for object value recursively call your getValue() function.
const input = { a:1, b:2, c:3, d:{ e:4, f:{ g:5, h:6 } } }
const getValue = (values) => {
for (const key of Object.keys(values)) {
if(typeof values[key] === 'object' && values[key] !== null) {
getValue(values[key]);
} else {
console.log(`${key}: ${values[key]}`);
}
}
}
getValue(input);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could use recursion to get the desired result.
const input = {
a: 1,
b: 2,
c: 3,
d: {
e: 4,
f: {
g: 5,
h: 6,
},
},
};
const result = {};
function getValues(obj) {
for (let key in obj) {
if (typeof obj[key] !== `object`) result[key] = obj[key];
else getValues(obj[key]);
}
}
getValues(input);
console.log(result);
Edited : you can do something like this
const input = {a:1,b:2,c:3,d:{e:4,f:{g:5,h:6 }}}
Object.assign({}, ...function _flatten(o) { return [].concat(...Object.keys(o).map(k => typeof o[k] === 'object' ? _flatten(o[k]) : ({[k]: o[k]})))}(input))
//{a: 1, b: 2, c: 3, e: 4, g: 5, …}
you can see more details here
JS CODE:
function deepEqual(obj1, obj2) {
f = false; //comparison result
if (Object.keys(obj1).join("") === Object.keys(obj2).join("")) { //checking if properties are equal
var table = Object.keys(obj1);
for (let entry of table) {
console.log("entry",entry); //outputs value
console.log("obj1",obj1);
console.log("obj1.entry",obj1.entry); // why is it undefined(if I write obj1.value it outputs 10)
if (obj1.entry == obj2.entry) {
f = true;
} else {
f = false;
break;
}
}
}
return f;
}
console.log(deepEqual({value:10},{value:10}));
Lot of issue with code, you can simplify it as below.
function deepEqual(obj1 = null, obj2 = null) {
if (obj1 === null || obj2 === null) return false;
if (typeof obj1 !== "object") return obj1 == obj2;
if (Object.keys(obj1).length !== Object.keys(obj2).length) return false;
for (let key in obj1) {
const result = deepEqual(obj1[key], obj2[key]);
if (!result) return false;
}
return true;
}
console.log(
deepEqual(
{ a: 10, value: 10, b: { c: 10 } },
{ b: { c: 10 }, value: 10, a: 10 }
)
);
console.log(
deepEqual(
{ a: 10, value: 10, b: { c: 10 } },
{ b: { c: 10, a: 1 }, value: 10, a: 10 }
)
);
I have below structure of array.
{
"a": "aa",
"**b**": {
"**b**": "bb",
"c": 1
},
"d": "d"
},
I want to display the end result like below.
{ "a": "aa",
"b": "bb",
"c": 1
"d": "dd"
},
I am trying with below code but its not working as expected.
let finalArr = [];
for (let [key, value] of Object.entries(resObj)) {
if (typeof value === 'object') {
for (let [keyInternal, valueInternal] of Object.entries(value)) {
valueInternal.map(arrValue => {
const finalObj = {
a: '',
b: '',
c : '',
d : ''
};
finalObj.a = key;
finalObj.b = arrValue[1].b;
finalObj.c = arrValue[1].c;
finalObj.d = keyInternal;
finalArr.push(finalObj);
});
}
}
}
You can use recursion to flatten you object something like this
let obj = {
"a": "aa",
"**b**": {
"**b**": "bb",
"c": 1,
},
"d": "d",
"*e*": {
"**e**": {
"e": 2
}
}
}
let flatten = (obj, final = {}) => {
Object.entries(obj).forEach(([key, value]) => {
if (typeof value === 'object') {
flatten(value, final)
} else {
final[key] = value
}
})
return final
}
console.log(flatten(obj))
Use forEach on entries and build new object. if the value is object then use Object.assign to flatten.
const obj = {
a: "aa",
b: {
b: "bb",
c: 1
},
d: "d"
};
const flatten = obj => {
const res = {};
Object.entries(obj).forEach(([key, value]) => {
if (typeof value === "object") {
Object.assign(res, value);
} else {
res[key] = value;
}
});
return res;
};
console.log(flatten(obj));
I have solved it using below way.
let finalArr = [];
for (let [key, value] of Object.entries(resObj)) {
if (typeof value === 'object') {
for (let [keyInternal, valueInternal] of Object.entries(value)) {
valueInternal.map(arrValue => {
const finalObj = {
a: '',
d: ''
};
finalObj.a= key;
finalObj.d= keyInternal;
var tempobj = {...finalObj,...arrValue};
finalArr.push(tempobj);
});
}
}
}
I have that object :
obj = {
a: true,
b: {
c: false,
d: true
}
What's the best way to check if all fields of my object is set to true. In case all fields are true => result should be true, if not => false.
This solution recursively checks if all the values are truthy.
const obj = {
a: true,
b: {
c: false,
d: true
}
}
const checkRecursive = (obj) => {
return Object.values(obj).every(el => typeof el === "object" ? checkRecursive(el) : el);
}
console.log(checkRecursive(obj));
Try this.
let obj = {
a: true,
b: {
c: false,
d: true
}
};
let objArray = []
function validate(obj) {
for(const item in obj) {
if(typeof obj[item] === 'object') {
validate(obj[item]);
} else {
objArray.push(obj[item]);
}
}
}
validate(obj);
// Use filter to check if there are any false value.
console.log(objArray.filter( item => !item).length === 0);
You can create your own recursive function with logic similar to the example below:
const obj = {
a: true,
b: {
c: {
d: true,
e: {
f: false
}
},
g: false,
h: {
i: false,
j: true,
k: {
l: false
}
}
},
m: {
n: true,
o: false,
p: {
q: {
r: {
s: {
t: true,
u: {
v: false,
w: true
}
}
}
}
}
}
}
function deepSearchForValue(o, searchValue) {
let found = false;
const level = [];
const keys = [];
function deepSearch(o) {
for (let [prop, value] of Object.entries(o)) {
if (value === searchValue) {
found = true;
keys.push(`${level.join('.')}.${prop}`);
} else if (typeof value === 'object') {
level.push(prop);
deepSearch(value);
level.pop();
}
}
}
deepSearch(o);
return [found, keys];
}
const [hasFalseValues, falseValueKeys] = deepSearchForValue(obj, false);
if (hasFalseValues) {
falseValueKeys.forEach(s => console.info(`false found at ${s}`));
}