Find specific property inside an object - javascript

I have an object. I want to check if a specific property exists in it or not.
The issue is: the property that I am looking for, could be anywhere, i.e: the structure of the object is undefiend.
ex:
obj1 = { "propIWant": "xyz" }
obj2 = { "prop1": [ {"key": "value"}, {"key":"value"}, 1, {"key": { "propIWant": "xyz"}}]
I've tried the following, but it seems to fail:
var lastTry = function(entry){
// if entry is an array
if(typeof entry === 'object' && entry instanceof Array){
for(var i in entry)
entry[i] = this.lastTry(entry[i]);
}
// if entry is a normal object
else if(typeof entry === 'object'){
// iterate through the properties of the entry
for(var key in entry){
console.log('key is: ', entry[key])
// in case the entry itself is an array
if(typeof entry[key] === 'object' && entry[key] instanceof Array){
for(var i in entry[key]){
entry[key][i] = this.lastTry(entry[key][i]);
}
}
// in case the entry is a simple object
else if(typeof entry[key] === 'object') {
console.log('entry[key] is an object', entry[key], key)
// if we directely find the property.. modify it
if(entry[key].hasOwnProperty('_internal_url')){
**entry[key]['_internal_url'] = "http://localhost:4000"+entry[key]['_internal_url'];** <-- My objective
}
else{
// call this method again on that part
// for(var i in entry[key]){
// if(typeof entry[key][i] === 'object')
// entry[key][i] = this.lastTry(entry[key][i]);
// }
}
}else{
console.log('not found')
}
}
}
}
Can someone please help me out with it?I found the following: Find by key deep in a nested object but, instead of returning the found part, I want to edit the property and return the entire object with the modified property, not just the subset of the object that has that property.

Have you tried :
obj1.hasOwnProperty('propIWant')

If you wish to just check if property exists or not, you can stringify the object and then check if value exists in string or not.
var obj2 = {
"prop1": [{
"key": "value"
}, {
"key": "value"
},
1, {
"key": {
"propIWant": "xyz"
}
}
]
}
var key = 'propIWant';
var key2 = 'propIWant1';
function isPropInObject(obj, prop) {
var r = new RegExp(prop + "\":")
var match = JSON.stringify(obj).match(r);
return match && match.length > 0 ? true : false
}
console.log(isPropInObject(obj2, key))
console.log(isPropInObject(obj2, key2))

Arrays and objects data can be access in a common way:
obj[key] and arr[pos];
This way you can simplify your code. Please note that key can be a string in case of a object or a number in case of an array.
The version below only searches in the element and eventual children elements(both arrays and objects) in a depth-first logic.
var found = 0;
var findProp = function(entry) {
if(typeof entry === 'object')
for(var key in entry) {
findProp(entry[key]);
if( entry[key].hasOwnProperty('_internal_url')) {
found++;
entry[key]['_internal_url'] = "http://localhost:4000" + entry[key]['_internal_url'];
}
}
}
console.log('found ' + found + 'occurrences');

Well, check if the props is objects themselves and use a recursive function to find the "deep" property you are looking for?
function findProp(obj, lookFor) {
for (var prop in obj) {
if (prop == lookFor) return obj[prop]
if (typeof obj[prop] == 'object') {
var checkNested = findProp(obj[prop], lookFor)
if (checkNested) return checkNested
}
}
return false
}
It works with console.log(findProp(obj2, 'propIWant'))
demo -> http://jsfiddle.net/zqcurg70/

Related

How to find the value of a dynamic key in javascript object

I have a javascript object
var obj = {a:{b:'value'}};
where key 'a' is dynamic, key 'b' is constant, so I am not able to get value from obj['a'].
Is there any way to get the value of key 'b' without knowing key 'a'.
You can find all the keys of object using Object.keys(<obj>)
In your case:
key = Object.keys(obj)[0]; // will return "a"
Use this:
var obj = {a:{b:'value'}};
obj[Object.keys(obj)[0]].b
You could use Object.values, like so:
const obj = { a: { b:'value' } };
Object.values(obj)[0].b // 'value'
Try this,
res = { data: { list: { names: { blk: { cnt: 10 } } } }, test:'test' };
let val = getObjectVal(res, 'cnt')
getObjectVal(data, findKey){
let result = '';
for (let key in data) {
if (key == findKey)
result = data[findKey];
if ((typeof data[key] === "object") && (data[key] !== null)) {
if (key != findKey)
result = getObjectVal(data[key], findKey)
}
}
return result ? result : '';}
To get the value of b
var obj = {a:{b:'value'}};
console.log(obj[Object.keys(obj)[0]].b)
var obj = {a:{b:'value'}};
// Looking for each object variables in obj
Object.keys(obj).forEach(function(key){
// Looking for each object variables in the obj[key]
Object.keys(obj[key]).forEach(function(key2){
// do what you want if key_2 is b
if(key2=='b')
console.log(obj[key][key2])
})
})

Find a key in nested object and replace its value - Javascript

Here is my fiddle : DEMO
By recursive iterations, I am able to find the key in object2 object3 and replace its value by the values from data2 data3 objects.
However, I am unable to replace the value if it is an array. (key called 'coordinates' in this case)
How could this be fixed?
function update(object, data) {
function getAllKeys(o) {
Object.keys(o).forEach(function(k) {
if (typeof o[k] === 'object') {
return getAllKeys(o[k]);
}
keys[k] = o;
});
}
var keys = Object.create(null);
getAllKeys(object);
Object.keys(data).forEach(function(k) {
if (keys[k] && k in keys[k]) { // check if key for update exist
keys[k][k] = data[k];
}
});
}
Update the getAllKeys method with:
function getAllKeys(o) {
Object.keys(o).forEach(function(k) {
contains_object = Array.isArray(o[k]) && o[k].some(val=> { return typeof val == "object" && !Array.isArray(val); });
if ((Array.isArray(o[k]) && !contains_object) || typeof o[k] !== 'object') {
keys[k] = o;
} else {
return getAllKeys(o[k]);
}
keys[k] = o;
});
}
Note: !(o[k] instanceof Array) - http://jsfiddle.net/08pnu7rx/1/
The problem is that typeof also returns object for arrays.
You want to change your function to still assign the key when the object is an array.
function getAllKeys(o) {
Object.keys(o).forEach(function(k) {
if (Array.isArray(o[k]) || typeof o[k] !== 'object') {
keys[k] = o;
} else {
return getAllKeys(o[k]);
}
});
}
Notice I swapped around the logic, so you first check for either an array or another non-object type. If that check passes, you assign the value. If not, you recurse.
You should note that this is not at all specific to arrays. You will have similar problems if you have a nested property that is a Date, for example.
The problem in your code is that typeof o[k] === 'object' returns true even it o[k] is an array which is the case for coordinated, You need a negative check for array too like
Object.keys(o).forEach(function(k) {
if (typeof o[k] === 'object'&& !Array.isArray(o[k])) {
return getAllKeys(o[k]);
}
keys[k] = o;
});
Working fiddle
According to the docs or typeof:
// use Array.isArray or Object.prototype.toString.call
// to differentiate regular objects from arrays
typeof [1, 2, 4] === 'object';

Get the location of an object in an array with JS/jQuery

Let's assume I have an array as following:
[
{
"name": "list",
"text": "SomeText1"
},
{
"name": "complex",
"text": "SomeText2",
"config": {
"name": "configItem",
"text": "SomeText3",
"anotherObject": {
"name": "anotherObject1",
"text": "SomeText4"
}
}
}
]
I am using this awesome code to get all Objects with a certain key (http://techslides.com/how-to-parse-and-search-json-in-javascript). In my example it is getObjects(data,'text','') which will return all nodes as Object due to the appearance of text as key.
My only problem is, that I need to know the location of the returned Object in the whole array.
Is there any way to get it? Or at least the depth of the object in conjunction to the array?
getObjects(r,'text','')[0] (name = list) -> depth 1
getObjects(r,'text','')[1] (name = complex) -> depth 1
getObjects(r,'text','')[2] (name = configItem) -> depth 2
You will need something along these lines:
function getObjectsDepth(obj, key, val, depth) {
var objects = [];
for (var i in obj) {
if (!obj.hasOwnProperty(i)) continue;
if (typeof obj[i] == 'object') {
objects = objects.concat(getObjectsDepth(obj[i], key, val,++depth));
} else
//if key matches and value matches or if key matches and value is not passed (eliminating the case where key matches but passed value does not)
if (i == key && obj[i] == val || i == key && val == '') { //
objects.push(depth);
} else if (obj[i] == val && key == ''){
//only add if the object is not already in the array
if (objects.lastIndexOf(obj) == -1){
objects.push(depth);
}
}
}
return objects;
}
This will return the depth of the object, but not the object itself, just pass a 0 or 1 as last param, based on how you want to count.
If you want both the object and the depth at the same time you need to obj.push({'obj':obj,'depth':depth}).
Change the getObjects function by this one:
function getObjects(obj, key, val, depth) {
var objects = [];
depth = typeof depth !== 'undefined' ? depth : 0;
for (var i in obj) {
if (!obj.hasOwnProperty(i)) continue;
if (typeof obj[i] == 'object') {
depth ++;
objects = objects.concat(getObjects(obj[i], key, val, depth));
} else
//if key matches and value matches or if key matches and value is not passed (eliminating the case where key matches but passed value does not)
if (i == key && obj[i] == val || i == key && val == '') { //
objects.push({"obj":obj,"depth": depth});
} else if (obj[i] == val && key == ''){
//only add if the object is not already in the array
if (objects.lastIndexOf(obj) == -1){
objects.push({"obj":obj,"depth": depth});
}
}
}
return objects;
}
Now you get depth and the object.

Resolve circular references from JSON object

If I have a serialized JSON from json.net like so:
User:{id:1,{Foo{id:1,prop:1}},
FooList{$ref: "1",Foo{id:2,prop:13}}
I want to have knockout output a foreach over FooList but I am not sure how to proceed because the $ref things could throw things.
I'm thinking the solution would be to somehow force all the Foos to be rendered in the FooList by not using:
PreserveReferencesHandling = PreserveReferencesHandling.Objects
but that seems wasteful..
I've found some bugs and implemented arrays support:
function resolveReferences(json) {
if (typeof json === 'string')
json = JSON.parse(json);
var byid = {}, // all objects by id
refs = []; // references to objects that could not be resolved
json = (function recurse(obj, prop, parent) {
if (typeof obj !== 'object' || !obj) // a primitive value
return obj;
if (Object.prototype.toString.call(obj) === '[object Array]') {
for (var i = 0; i < obj.length; i++)
// check also if the array element is not a primitive value
if (typeof obj[i] !== 'object' || !obj[i]) // a primitive value
continue;
else if ("$ref" in obj[i])
obj[i] = recurse(obj[i], i, obj);
else
obj[i] = recurse(obj[i], prop, obj);
return obj;
}
if ("$ref" in obj) { // a reference
var ref = obj.$ref;
if (ref in byid)
return byid[ref];
// else we have to make it lazy:
refs.push([parent, prop, ref]);
return;
} else if ("$id" in obj) {
var id = obj.$id;
delete obj.$id;
if ("$values" in obj) // an array
obj = obj.$values.map(recurse);
else // a plain object
for (var prop in obj)
obj[prop] = recurse(obj[prop], prop, obj);
byid[id] = obj;
}
return obj;
})(json); // run it!
for (var i = 0; i < refs.length; i++) { // resolve previously unknown references
var ref = refs[i];
ref[0][ref[1]] = byid[ref[2]];
// Notice that this throws if you put in a reference at top-level
}
return json;
}
The json object which you are receiving from the server contains Circular References. Before using the object you should have to first remove all the $ref properties from the object, means in place of $ref : "1" you have to put the object which this link points.
In your case may be it is pointing to the User's object whose id is 1
For this you should check out Douglas Crockfords Plugin on github.There is a cycle.js which can do the job for you.
or you can use the following code (not tested) :
function resolveReferences(json) {
if (typeof json === 'string')
json = JSON.parse(json);
var byid = {}, // all objects by id
refs = []; // references to objects that could not be resolved
json = (function recurse(obj, prop, parent) {
if (typeof obj !== 'object' || !obj) // a primitive value
return obj;
if ("$ref" in obj) { // a reference
var ref = obj.$ref;
if (ref in byid)
return byid[ref];
// else we have to make it lazy:
refs.push([parent, prop, ref]);
return;
} else if ("$id" in obj) {
var id = obj.$id;
delete obj.$id;
if ("$values" in obj) // an array
obj = obj.$values.map(recurse);
else // a plain object
for (var prop in obj)
obj[prop] = recurse(obj[prop], prop, obj)
byid[id] = obj;
}
return obj;
})(json); // run it!
for (var i=0; i<refs.length; i++) { // resolve previously unknown references
var ref = refs[i];
ref[0][ref[1]] = byid[refs[2]];
// Notice that this throws if you put in a reference at top-level
}
return json;
}
Let me know if it helps !
This is actually extremely simple if you take advantage of JSON.parse's reviver parameter.
Example below. See browser console for the output because StackOverflow's snippet console output will not provide an accurate picture of what the result is.
// example JSON
var j = '{"$id":"0","name":"Parent",' +
'"child":{"$id":"1", "name":"Child","parent":{"$ref":"0"}},' +
'"nullValue":null}';
function parseAndResolve(json) {
var refMap = {};
return JSON.parse(json, function (key, value) {
if (key === '$id') {
refMap[value] = this;
// return undefined so that the property is deleted
return void(0);
}
if (value && value.$ref) { return refMap[value.$ref]; }
return value;
});
}
console.log(parseAndResolve(j));
<b>See actual browser console for output.</b>
I had trouble with the array correction in the answer of Alexander Vasiliev.
I can't comment his answer (don't own enough reputations points ;-) ), so I had to add a new answer...
(where I had a popup as best practice not to answer on other answers and only on the original question - bof)
if (Object.prototype.toString.call(obj) === '[object Array]') {
for (var i = 0; i < obj.length; i++) {
// check also if the array element is not a primitive value
if (typeof obj[i] !== 'object' || !obj[i]) // a primitive value
return obj[i];
if ("$ref" in obj[i])
obj[i] = recurse(obj[i], i, obj);
else
obj[i] = recurse(obj[i], prop, obj);
}
return obj;
}
In the accepted implementation, if you're inspecting an array and come across a primitive value, you will return that value and overwrite that array. You want to instead continue inspecting all of the elements of the array and return the array at the end.
function resolveReferences(json) {
if (typeof json === 'string')
json = JSON.parse(json);
var byid = {}, // all objects by id
refs = []; // references to objects that could not be resolved
json = (function recurse(obj, prop, parent) {
if (typeof obj !== 'object' || !obj) // a primitive value
return obj;
if (Object.prototype.toString.call(obj) === '[object Array]') {
for (var i = 0; i < obj.length; i++)
// check also if the array element is not a primitive value
if (typeof obj[i] !== 'object' || !obj[i]) // a primitive value
continue;
else if ("$ref" in obj[i])
obj[i] = recurse(obj[i], i, obj);
else
obj[i] = recurse(obj[i], prop, obj);
return obj;
}
if ("$ref" in obj) { // a reference
var ref = obj.$ref;
if (ref in byid)
return byid[ref];
// else we have to make it lazy:
refs.push([parent, prop, ref]);
return;
} else if ("$id" in obj) {
var id = obj.$id;
delete obj.$id;
if ("$values" in obj) // an array
obj = obj.$values.map(recurse);
else // a plain object
for (var prop in obj)
obj[prop] = recurse(obj[prop], prop, obj);
byid[id] = obj;
}
return obj;
})(json); // run it!
for (var i = 0; i < refs.length; i++) { // resolve previously unknown references
var ref = refs[i];
ref[0][ref[1]] = byid[ref[2]];
// Notice that this throws if you put in a reference at top-level
}
return json;
}
my solution(works for arrays as well):
usage: rebuildJsonDotNetObj(jsonDotNetResponse)
The code:
function rebuildJsonDotNetObj(obj) {
var arr = [];
buildRefArray(obj, arr);
return setReferences(obj, arr)
}
function buildRefArray(obj, arr) {
if (!obj || obj['$ref'])
return;
var objId = obj['$id'];
if (!objId)
{
obj['$id'] = "x";
return;
}
var id = parseInt(objId);
var array = obj['$values'];
if (array && Array.isArray(array)) {
arr[id] = array;
array.forEach(function (elem) {
if (typeof elem === "object")
buildRefArray(elem, arr);
});
}
else {
arr[id] = obj;
for (var prop in obj) {
if (typeof obj[prop] === "object") {
buildRefArray(obj[prop], arr);
}
}
}
}
function setReferences(obj, arrRefs) {
if (!obj)
return obj;
var ref = obj['$ref'];
if (ref)
return arrRefs[parseInt(ref)];
if (!obj['$id']) //already visited
return obj;
var array = obj['$values'];
if (array && Array.isArray(array)) {
for (var i = 0; i < array.length; ++i)
array[i] = setReferences(array[i], arrRefs)
return array;
}
for (var prop in obj)
if (typeof obj[prop] === "object")
obj[prop] = setReferences(obj[prop], arrRefs)
delete obj['$id'];
return obj;
}

How can I find key in JavaScript Object when his depth is unknown?

If I have an javascript object like this: {a : { b: { c: { ... }}}}, how can I find if there is an 'x' key in the object and what it's value ?
So long as their is no fear of cyclic references you could do the following
function findX(obj) {
var val = obj['x'];
if (val !== undefined) {
return val;
}
for (var name in obj) {
var result = findX(obj[name]);
if (result !== undefined) {
return result;
}
}
return undefined;
}
Note: This will search for the property 'x' directly in this object or it's prototype chain. If you specifically want to limit the search to this object you can do so doing the following
if (obj.hasOwnProperty('x')) {
return obj['x'];
}
And repeating for pattern for the recursive calls to findX
function hasKey(obj,key){
if(key in obj)
return true;
for(var i in obj)
if(hasKey(obj[i],key))
return true;
return false;
}
ex:
alert(hasKey({a:{b:{c:{d:{e:{f:{g:{h:{i:{}}}}}}}}}},'i'));

Categories