finding property in js object by name - javascript

I've got many objects that structures aren't the same. But I know that all of them have got property name 'siteName'. My question is how can I get value from this property.
Explame of few objects:
feature1 = {
display: "name",
feature: {
attributes: {
when: '111',
what: '222'
},
geometry: null
infoTemplate: undefined
},
symbol: null
siteName: 'aa'
}
feature2 = {
feature: {
attributes: {
when: '111',
what: '222'
},
geometry: null
infoTemplate: undefined
},
static: {
format: {
weight: 12,
siteName: 'cccc'
},
}
}

Here's a recursive function that should work for you.
It returns the value of the first property found with the name, otherwise returns undefined.
function findByName(obj, prop) {
for (var p in obj) {
if (p === prop) {
return obj[p];
} else if (obj[p] && typeof obj[p] === "object") {
var result = findByName(obj[p], prop);
if (result !== undefined)
return result;
}
}
}
var result = findByName(myObject, "siteName");
Or here's another variation that avoids inherited properties.
function findByName(obj, prop) {
if (obj.hasOwnProperty(prop))
return obj[prop];
for (var p in obj) {
if (obj[p] && typeof obj[p] === "object") {
var result = findByName(obj[p], prop);
if (result !== undefined)
return result;
}
}
}

Recursively loop through the objects:
function find(obj, name) {
for (var k in obj) { // Loop through all properties of the object.
if(k == name){ // If the property is the one you're looking for.
return obj[k]; // Return it.
}else if (typeof obj[k] == "object"){ // Else, if the object at [key] is a object,
var t = find(obj[k], name); // Loop through it.
if(t){ // If the recursive function did return something.
return t; // Return it to the higher recursion iteration, or to the first function call.
}
}
}
}
Usage:
find(feature1, "siteName"); //Returns "aa"

The following function should suit your needs:
function getFirstFoundPropertyValue(searchedKey, object) {
if(typeof object === "object") {
for (var key in object) {
var currentValue = object[key];
if(key === searchedKey) {
return currentValue;
}
var nested = getFirstFoundPropertyValue(searchedKey, currentValue);
if(typeof nested !== "undefined") {
return nested;
}
}
}
}
It returns the value of the key if the key is found, undefined otherwise. If the key appears several times, the first found one will be returned.

Related

All object property is not empty javascript

How to check the following object, make sure every property is not equal to undefined, null or empty string?
userObj = {
name: {
first: req.body.first,
last: req.body.last
},
location: {
city: req.body.city
},
phone: req.body.phone
}
I can check req.body one by one like if(req.body.first) but that's too tedious if I have many params.
You can simply use Array.prototype.some() method over Object.values() to implement this in a recursive way:
function isThereAnUndefinedValue(obj) {
return Object.values(obj).some(function(v) {
if (typeof v === 'object'){
if(v.length && v.length>0){
return v.some(function(el){
return (typeof el === "object") ? isThereAnUndefinedValue(el) : (el!==0 && el!==false) ? !el : false;
});
}
return isThereAnUndefinedValue(v);
}else {
console.log(v);
return (v!==0 && v!==false) ? !v : false;
}
});
}
In the following function we will:
Loop over our object values.
Check if the iterated value is an object we call the function recursively with this value.
Otherwise we will just check if this is a truthy value or not.
Demo:
This is a working Demo:
userObj = {
name: {
first: "req.body.first",
last: [5, 10, 0, 40]
},
location: {
city: "req.body.city"
},
phone: "req.body.phone"
}
function isThereAnUndefinedValue(obj) {
return Object.values(obj).some(function(v) {
if (typeof v === 'object'){
if(v.length && v.length>0){
return v.some(function(el){
return (typeof el === "object") ? isThereAnUndefinedValue(el) : (el!==0 && el!==false) ? !el : false;
});
}
return isThereAnUndefinedValue(v);
}else {
console.log(v);
return (v!==0 && v!==false) ? !v : false;
}
});
}
console.log(isThereAnUndefinedValue(userObj));
You will get a function that validates every object and its sub objects in a recursive way.
To check for truthy values (values other than false, '', 0, null, undefined):
const hasOnlyTruthyValues = obj => Object.values(obj).every(Boolean);
Example:
const hasOnlyTruthyValues = obj => Object.values(obj).every(Boolean);
const object = {
a: '12',
b: 12,
c: ''
};
console.log(hasOnlyTruthyValues(object));
The example you posted (if (res.body.first) ...) also checks for a truthy value. If you want to allow false and 0 (which are falsy, but you didn't mention them in your question), use:
const hasOnlyAllowedValues = obj => Object.values(obj).every(v => v || v === 0 || v === false);
you can create a simple validator for yourself like function below
var body = {
a: 1,
b: 3
};
var keys = ['a', 'b', 'c'];
function validate(body, keys) {
for (var i in keys) {
if (!body[keys[i]]) {
return false;
}
}
return true;
}
console.log(validate(body, keys));
you can use the following validator to check, it works for a nested object as well
function objectValidator(obj){
let ret = true;
for(property in obj){
//console.log(property, obj[property], typeof obj[property]);
if(typeof obj[property] == "object"){
if(obj[property] instanceof Array){
ret = (ret & true);
}
else if(obj[property] == null){
ret = false;
}
else{
ret = (ret & objectValidator(obj[property]));
}
}
else if(typeof obj[property] == "string"){
if(obj[property] == ""){
ret = false;
}
}
else if(typeof obj[property] == "undefined"){
ret = false;
}
}
return ret;
}
let a = {
b : 1,
c :{
d: 2,
e: [3, 4],
f : ""
}
}
console.log(objectValidator(a));
In your post you use:
if(req.body.first)
I don't know if you are checking req and body before hand, but this should be:
if ( typeof req == "object" && typeof req.body == "object"
&& req.body.first ) {
That is a safer way to check before use.
Or, if you want to embed in the object:
function fnTest(a,b,c) {
return (typeof a == "object" && typeof b == "object" && c) ? c : "";
};
userObj = {name:{
first: fnTest(req, req.body, req.body.first)
,last: fnTest(req,req.body, req.body.last)
},location:{
city: fnTest(req,req.body,req.body.city)
},phone: fnTest(req.body.phone)
};

recursively remove undefined from object (including parent)

I'm trying to find a solution to a problem where I need to remove undefined from nested object including all parents if there are no values there, please consider example:
var test = {
foo : {
bar : {
baz : undefined
}
},
bar : 1
}
So my task is to remove baz along with bar and foo but still have bar at the root level;
I know that it's trivial task to solve with 2 for loops, I'm just wondering if there are more elegant and clean solutions which will use recursive stack instead?
Thanks in advance!
Depth-first recursion should be able to handle it:
function cleanse(obj, path) {
Object.keys(obj).forEach(function(key) {
// Get this value and its type
var value = obj[key];
var type = typeof value;
if (type === "object") {
// Recurse...
cleanse(value);
// ...and remove if now "empty" (NOTE: insert your definition of "empty" here)
if (!Object.keys(value).length) {
delete obj[key]
}
}
else if (type === "undefined") {
// Undefined, remove it
delete obj[key];
}
});
}
Example:
var test = {
foo : {
bar : {
baz : undefined
}
},
bar : 1
};
cleanse(test);
function cleanse(obj, path) {
Object.keys(obj).forEach(function(key) {
// Get this value and its type
var value = obj[key];
var type = typeof value;
if (type === "object") {
// Recurse...
cleanse(value);
// ...and remove if now "empty" (NOTE: insert your definition of "empty" here)
if (!Object.keys(value).length) {
delete obj[key]
}
}
else if (type === "undefined") {
// Undefined, remove it
delete obj[key];
}
});
}
console.log(test);
Note that that only visits own, enumerable properties of the objects whose names are not Symbols (ES2015+). If you also want to handle properties inherited from prototypes, or non-enumerable properties, or properties whose names are Symbols, you'll need to adjust to handle that. (You can get non-enumerable properties on an ES5 or later JavaScript engine via getOwnPropertyNames.)
Below example can help you get started.
Without delete keys with empty values:
var test = {
foo: {
bar: {
baz: undefined,
bar: {
baz: undefined
}
}
},
bar: 1,
baz: undefined
}
function loop(obj) {
var t = obj;
for (var v in t) {
if (typeof t[v] == "object")
loop(t[v]);
else if (t[v] == undefined)
delete t[v];
}
return t;
}
var output = loop(test);
console.log(output);
Deleting keys with empty values:
var test = {
foo: {
bar: {
baz: undefined,
bar: {
baz: undefined
}
}
},
bar: 1,
baz: undefined
}
function loop(obj) {
var t = obj;
for (var v in t) {
if (typeof t[v] == "object")
if (!t[v].length)
delete t[v];
else
loop(t[v]);
else if (t[v] == undefined)
delete t[v];
}
return t;
}
var output = loop(test);
console.log(output);
IMO this is much cleaner but probably a smidge slower
const cleanUndefined = object => JSON.parse(JSON.stringify(object));
const testWithoutUndefined = cleanUndefined(test)
I took the function proposed by #T.J. Crowder and changed it to use for ... of and Object.entries(obj). I also return the object for convenience.
function cleanseObject(obj) {
for (const [key, value] of Object.entries(obj)) {
if (typeof value === 'object') {
cleanseObject(value)
if (!Object.keys(value).length) delete obj[key]
} else if (typeof value === 'undefined') {
delete obj[key]
}
}
return obj
}
function cleanPayload(obj: any) {
Object.keys(obj).forEach(key => {
const value = obj[key];
const type = typeof value;
if (!value || !type) {
delete obj[key];
} else if (type === 'object') {
cleanPayload(value);
if (!Object.keys(value).length) {
if (key != 'attributes') {
delete obj[key];
}
}
}
});
return obj;
}
Without mutating the original object
const cleanse = obj => {
const newObj = Array.isArray(obj) ? [...obj] : { ...obj };
Object.keys(newObj).forEach((key) => {
// Get this value and its type
const value = newObj[key];
var type = typeof value;
if (type === "object") {
// Recurse...
newObj[key] = cleanse(value);
// ...and remove if now "empty" (NOTE: insert your definition of "empty" here)
if (!Object.keys(value).length) {
delete newObj[key]
}
}
else if (type === "undefined") {
// Undefined, remove it
delete newObj[key];
}
});
return newObj;
};
console.log(
cleanse({ a: { b: undefined, c: 22 }}),
cleanse({ a: [{ b: undefined, c: 22 }] }),
);
Here is the code, which will also remove that undefined contained key and empty object from the main object.
var test = {
foo: {
bar: {
baz: undefined,
bar: {
baz: undefined,
}
}
},
bar: 1,
baz: undefined
}
function loop(obj) {
var t = obj;
for (var v in t) {
if (typeof t[v] == "object"){
loop(t[v]);
if(!Object.keys(t[v]).length){
delete t[v];
}
} else if (t[v] == undefined){
delete t[v];
}
}
return t;
}
var output = loop(test);
console.log(output);

Checking existence of nested property in an object javascript

I have already reviewed some of the answers to similar questions, however, I want to ask my question differently.
Let's say we have a string like "level1.level2.level3. ..." that indicates a nested property in an object called Obj.
The point is that we may not know how many nested properties exist in this string. For instance, it may be "level1.level2" or "level1.level2.level3.level4".
Now, I want to write a function, that given the Obj and the string of properties as input, to simply tell us if such a nested property exists in the object or not (let's say true or false as output).
Update:
Thanks to #Silvinus, I found the solution with a minor modification:
private checkNestedProperty(obj, props) {
var splitted = props.split('.');
var temp = obj;
for (var index in splitted) {
if (temp[splitted[index]] === 'undefined' || !temp[splitted[index]]) return false;
temp = temp[splitted[index]];
}
return true;
}
You could use Array#every() and thisArg of it, by iterating the keys and checking if it is in the given object.
var fn = function (o, props) {
return props.split('.').every(k => k in o && (o = o[k], true));
}
console.log(fn({}, "toto.tata")); // false
console.log(fn({ toto: { tata: 17 } }, "toto.tata")); // true
console.log(fn({ toto: { tata: { tutu: 17 } } }, "toto.foo.tata")); // false
console.log(fn({ toto: { tata: false } }, "toto.tata")); // true
You can explore your Obj with this function :
var fn = function(obj, props) {
var splited = props.split('.');
var temp = obj;
for(var index in splited) {
if(typeof temp[splited[index]] === 'undefined') return false;
temp = temp[splited[index]]
}
return true
}
var result = fn({ }, "toto.tata");
console.log(result); // false
var result = fn({ toto: { tata: 17 } }, "toto.tata");
console.log(result); // true
var result = fn({ toto: { tata: { tutu: 17 } } }, "toto.foo.tata");
console.log(result); // false
This function allow to explore nested property of Obj that depends of props passed in parameter
This answer provides the basic answer to your question. But it needs to be tweaked to handle the undefined case:
function isDefined(obj, path) {
function index(obj, i) {
return obj && typeof obj === 'object' ? obj[i] : undefined;
}
return path.split(".").reduce(index, obj) !== undefined;
}
Based on the solution given by #Silvinus here is a solution if you deal with array inside nested objects (as it is often the case in results from databases queries) :
checkNested = function(obj, props) {
var splited = props.split('.');
var temp = obj;
for(var index in splited) {
var regExp = /\[([^)]+)\]/;
var matches = regExp.exec(splited[index])
if(matches) {
splited[index] = splited[index].replace(matches[0], '');
}
if(matches) {
if(matches && typeof temp[splited[index]][matches[1]] === 'undefined') return false;
temp = temp[splited[index]][matches[1]];
}
else {
if(!matches && typeof temp[splited[index]] === 'undefined') return false;
temp = temp[splited[index]]
}
}
return true
}
obj = {ok: {ao: [{},{ok: { aa: ''}}]}}
console.log(checkNested(obj, 'ok.ao[1].ok.aa')) // ==> true
console.log(checkNested(obj, 'ok.ao[0].ok.aa')) // ==> false

How can I filter an object of all properties that are objects?

I'm trying to make a copy of an object that only includes the properties that are not objects. But the child objects get copied along with it.
var testObject = {
stringProperty: "hi",
intProperty: 4,
objectProperty: {},
nullProperty: null
};
console.log(removeChildObjects(testObject));
function removeChildObjects(object) {
var keys = Object.keys(object);
var newObject = {};
keys.forEach(function(key) {
console.log(key, object[key], typeof object[key]);
if (typeof object[key] != "object") {
newObject[key] = object[key];
}
});
return object;
}
Also check it out here https://jsfiddle.net/uss94sc3/1/
If you want to strictly filter out object properties (keeping null and undefined properties), then you cannot rely on the broken typeof unary operator.
typeof null
// "object"
You can either change your code to:
function removeChildObjects(object) {
var keys = Object.keys(object);
var newObject = {};
keys.forEach(function(key) {
if (typeof object[key] != "object" || object[key] == null) {
newObject[key] = object[key];
}
});
return newObject;
}
or more succinctly with underscore:
function removeChildObjects(object) {
return _.omit(object, _.isObject);
}
You return the same object that passed:
return object;
You should return newObject
return newObject;
Try replacing return object; with return newObject;. It will work a lot better!
https://jsfiddle.net/w3urvpjq/
You may try this
var testObject = {
stringProperty: "hi",
intProperty: 4,
objectProperty: {},
nullProperty: null
};
var filterPrimitive = o => Object.keys(o).reduce((p,k) => {typeof o[k] != "object" && (p[k] = o[k]); return p},{});
document.write("<pre>" + JSON.stringify(filterPrimitive(testObject),null,2) + "</pre>");

Dig till deepest .value or .content

I am trying to write a function that digs an object till it gets to the last .value or .content property. I wrote this and for the life of me I cant figure out why it breaks.
var jscGetDeepest = function(obj) {
try {
console.info(Math.round(Math.random() * 10) + ' starting jscGetDeepest:', obj, obj.toString());
} catch(ignore) {}
while (obj && ('contents' in obj || 'value' in obj)) {
if ('contents' in obj) {
obj = obj.contents;
} else if ('value' in obj) {
obj = obj.value;
}
//console.info('loop jscGetDeepest:', obj.toString());
}
if (obj || obj === 0) {
obj = obj.toString();
}
console.info('finaled jscGetDeepest:', obj);
return obj;
}
The issue occurs when inner value in the next iteration is not an object. In this case you get an error message, because in operand can't be used with primitives.
To fix it check for object before trying to get deeper. Here is a fixed an slightly improved version with JSON.stringify instead of toString (maybe better to return object itself without stringifying it?):
var jscGetDeepest = function (obj) {
while (typeof obj === 'object' && obj !== null && ('contents' in obj || 'value' in obj)) {
if ('contents' in obj) {
obj = obj.contents;
} else if ('value' in obj) {
obj = obj.value;
}
}
if (typeof obj === 'object') {
obj = JSON.stringify(obj);
}
return obj;
}
alert( jscGetDeepest({value: {name: 2, contents: {name: 3, value: 23}}}) );
alert( jscGetDeepest({value: {name: 2, value: {name: 3, contents: {name: 4}}}}) );

Categories

Resources