Transform an object recursively in JavaScript - javascript

I've been struggling with that problem for a few days. I have to transform an object into another object with a different structure.
from this:
{
"a1" : "key",
"a2" : {
"b1" : "key",
"b2" : {
"c1" : "key"
}
}
}
to this:
{
"key" : {
"a1" : null,
"a2" : [
{
"b1" : null,
},
{
"b2" : [
"c1" : null
]
}
]
}
}
For better understanding, a1, a2, b1, b3 etc. would represent css selectors. null will be the value applied to the node. But for now, this shouldn't matter.
My current (non working) function looks like this:
var json = {};
var obj = {};
function build(objA){
for(var a in objA){
var key = objA[a];
if(key instanceof Object){
obj = {}; obj[a] = key;
build(key);
} else {
json[key] = json[key] || {};
if(obj == undefined){
json[key][a] = null;
} else {
var p = firstKeyOf(obj);
var key = obj[p][a];
json[key][p] = json[key][p] || [];
var selector = {};
selector[a] = null;
json[key][p].push(selector);
}
}
}
}
which produces:
{
"key" : {
"a1" : null,
"a2" : [
{
"b1" : null
}
],
"b2" : [
{
"c1" : null
}
]
}
}
What did i miss? I appreciate any help, thanks!

Try this
var Converter = (function() {
var pic;
function _rec(a, o) {
for(var k in o){
var s = o[k];
var arr = a.slice();
arr.push(k);
if (s instanceof Object) { _rec(arr, s); }
else {
if ("string" == typeof s) { arr.unshift(s); _attach(pic, arr); }
else console.log('Invalid key type');
}
}
}
function _attach(p, m) {
var k = m.shift();
if ( ! p.hasOwnProperty(k)) p[k] = (m.length == 0) ? null : {};
if (m.length > 0) p[k] = _attach(p[k], m);
return p;
}
function _reverse(obj) {
if ( ! (obj instanceof Object)) console.log('First parameter need to be an Object');
else { pic = {}; _rec([], obj); return pic; }
}
return {
reverse: _reverse,
attach: _attach
}
})();

Related

How can I manipulate an object's structure into a 'dot notation'-style array

I am working on a project using Meteor, which connects to an external API with Mongoose (With Meteor.HTTP). I have nested objects whose source data looks like this:
{name: "asdasd", active: true, status: Object, domain: "asdas", category: "1"…}
I need to POST/PUT the data in this format:
{
active: true,
category: "1",
contact.companyName: "asd",
contact.email: "asd",
contact.managerName: "asd",
contact.phone: "asd",
domain: "asdasd",
name: "asjdnas",
ImagePaths: ["asdasdad","asdasdAsd"],
}
without nested style objects, or any kind of:
ImagePaths[0] : asdasdad,
ImagePaths[1] : asdasdad
sites:
0: "565f1c7da35dcaa718713f4f"
etc. I found this code (by #rhalff)
var dotize = dotize || {};
dotize.parse = function(jsonobj, prefix) {
var newobj = {};
function recurse(o, p) {
for (var f in o)
{
var pre = (p === undefined ? '' : p + ".");
if (o[f] && typeof o[f] === "object"){
newobj = recurse(o[f], pre + f);
} else {
newobj[pre + f] = o[f];
}
}
return newobj;
}
return recurse(jsonobj, prefix);
};
But I'm still having problems with arrays. They are appearing like this:
Paths.0: "asdkmalksmdasd",
Paths.1: "asdasdad",
What I need is this:
Paths:["asdkmalksmdasd","asdasdad"];
You can play it here on jsbin: https://jsbin.com/kadivewoti/edit?js,console
How can I achieve this?
I added one if-statement to the code:
var dotize = dotize || {};
dotize.parse = function(jsonobj, prefix) {
var newobj = {};
function recurse(o, p) {
for (var f in o)
{
var pre = (p === undefined ? '' : p + ".");
if(o[f] && o[f].length){
newobj[f] = o[f];
}
else if (o[f] && typeof o[f] === "object"){
newobj = recurse(o[f], pre + f);
}
else {
newobj[pre + f] = o[f];
}
}
return newobj;
}
return recurse(jsonobj, prefix);
};
var mydata = '{"name":"asjdnas","active":true,"status":{"pending":true,"comment":"asdasd"},"domain":"asdasd","category":"1","contact":{"companyName":"asd","managerName":"asd","phone":"asd","email":"asd"},"server":{"os":"akjsdn"},"Paths":["asdkmalksmdasd","asdasdad"]}';
mydata = JSON.parse(mydata);
mydata = dotize.parse(mydata);
console.log(mydata);
Namely
if(o[f] && o[f].length){
newobj[f] = o[f];
}

traversing a json for empty array value

i have a below json
{
"loanDetails": [
{
"vehicleDetail": {
"RCBookImageReferences": {
"imagePathReferences": [
{
}
]
}
},
"chargeDetails": [
{
}
],
"commissionDetails": [
{
}
],
"disbursementDetails": [
{
}
]
}
]
}
in the above json i need to traverse every key and if i find it emty then set the parent as empty array ie the output should be as below
{"loanDetails":[]}
i used the code below
function isEmpty(obj) {
for(var prop in obj) {
if(obj.hasOwnProperty(prop))
return false;
}
return true;
}
But it did not give me the expected result.I'm stuck here any help will be much helpful.
The function clean takes an object and loops over its keys, calling clean recursively
on each object-valued property.
If the result of cleaning is an empty object, delete the key in question.
If the object itself turns out to be empty, return undefined, triggering deletion of the property holding that object at the higher level.
function clean(obj) {
var isEmpty = true;
for (var key in obj) {
var val = obj[key];
if (val === null || typeof val !== 'object' || (obj[key] = clean(val))) {
isEmpty = false;
} else {
delete obj[key];
}
}
return isEmpty ? undefined : obj;
}
>> a = { x: 1, b: { y: [] }, c: { d: { } } }
>> clean(a)
<< Object {x: 1}
This should make it recursive. With two solutions.
Solution 1: empty test function
var boolValue = true;
for(var prop in obj) {
if(obj.hasOwnProperty(prop) && typeof obj[prop] === 'object')
{
boolValue = recursiveIsEmpty(obj[prop]);
}
else
{
return false;
}
}
return boolValue ;
//test and set empty string
recursiveIsEmpty(jsonDataObj['loanDetails']) ? jsonDataObj['loanDetails'] = [] : null;
Solution 2 recursive empty function that empties parent obj
function recursiveIsEmpty(obj) {
var boolValue = true;
for(var prop in obj) {
if(obj.hasOwnProperty(prop) && typeof obj[prop] === 'object')
{
boolValue = recursiveIsEmpty(obj[prop]);
if (boolValue)
{
delete obj[prop]; //an object is empty. Delete from parent;
}
}
else
{
return false;
}
}
return boolValue; //returns an empty object
}
recursiveIsEmpty(jsonDataObj['loanDetails']) //returns jsonDataObj['loanDetails'] = [];
This checks if obj has a property that is an object. If so load that object and check it's properties. If not return false, because that will be string or number and that confirms the object is not empty.
Your JSON-string is not valid. When corrected, you can use a reviver function parameter (see MDN) to remove 'empty' arrays (aka properties with criteria you specify).
To be clear, the reviver function takes care of the traversing on all levels of the parsed object. If it returns undefined the property is removed from the object. The reviver used in the snippet thus removes all properties containing arrays with empty objects, or empty arrays.
The snippet demonstrates this.
// json string corrected
var foo = '{"loanDetails": [{"vehicleDetail": {"RCBookImageReferences": '+
'{"imagePathReferences": [{}]}}, "chargeDetails": [{}],'+
'"commissionDetails": [{}],"disbursementDetails": [{}]}]}';
// parse it, using reviver parameter
var fooparsed = JSON.parse( foo,
function (key, value) { //<= reviver here
return (value.length && value.length == 1 &&
value[0] instanceof Object &&
Object.keys(value[0]).length == 0) ||
value instanceof Array && !value.length
? undefined : value;
}
);
// print
Helpers.log2Screen( Object.print(fooparsed) );
<script src="http://kooiinc.github.io/JSHelpers/Helpers-min.js"></script>
if you are doing this using ajax then you should go with seriallizing the jason array using javascript.
at the time of passing data through json
data: "your data",
use this
data:$(form).serialize(),
it will pass all the key of that form which you are passing ,
if you want to see its result the try to print it on console
var inputObj = {
"loanDetails": [{
"vehicleDetail": {
"RCBookImageReferences": {
"imagePathReferences": [{}]
}
},
"chargeDetails": [{}],
"commissionDetails": [{}],
"disbursementDetails": [{}]
}, {
"vehicleDetail": {
"RCBookImageReferences": {
"imagePathReferences": [{
"Valid": "Working"
}]
}
},
"chargeDetails": [{}],
"commissionDetails": [{}],
"disbursementDetails": [{}]
}],
"Superman": {
"Name": ""
},
"SpiderMan": {
"Name": "Senthil"
}
}
function flatten(target, opts) {
var output = {},
opts = opts || {},
delimiter = opts.delimiter || '.'
function getkey(key, prev) {
return prev ? prev + delimiter + key : key
};
function step(object, prev) {
Object.keys(object).forEach(function(key) {
var isarray = opts.safe && Array.isArray(object[key]),
type = Object.prototype.toString.call(object[key]),
isobject = (type === "[object Object]" || type === "[object Array]")
if (!isarray && isobject) {
return step(object[key], getkey(key, prev))
}
output[getkey(key, prev)] = object[key]
});
if (Object.keys(object) == "") {
if (object instanceof Array) {
output[prev] = [];
} else {
output[prev] = {};
}
}
};
step(target)
return output
};
function unflatten(target, opts) {
var opts = opts || {},
delimiter = opts.delimiter || '.',
result = {}
if (Object.prototype.toString.call(target) !== '[object Object]') {
return target
}
function getkey(key) {
var parsedKey = parseInt(key)
return (isNaN(parsedKey) ? key : parsedKey)
};
Object.keys(target).forEach(function(key) {
var split = key.split(delimiter),
firstNibble, secondNibble, recipient = result
firstNibble = getkey(split.shift())
secondNibble = getkey(split[0])
while (secondNibble !== undefined) {
if (recipient[firstNibble] === undefined) {
recipient[firstNibble] = ((typeof secondNibble === 'number') ? [] : {})
}
recipient = recipient[firstNibble]
if (split.length > 0) {
firstNibble = getkey(split.shift())
secondNibble = getkey(split[0])
}
}
// unflatten again for 'messy objects'
recipient[firstNibble] = unflatten(target[key])
});
//Array Check
var keys = Object.keys(result);
if (keys.length > 0 && keys[0] === "0") {
var output = [];
keys.forEach(function(key) {
output.push(result[key])
});
return output;
}
return result
};
var flatted = flatten(inputObj);
var keys = Object.keys(flatted);
keys.forEach(function(key) {
if (JSON.stringify(flatted[key]) === "{}" || JSON.stringify(flatted[key]) == "") {
// console.log(key)
delete flatted[key];
var paths = key.split(".");
if (paths.length >= 2) {
var int = parseInt(paths[1])
if (isNaN(int)) {
key = paths[0];
flatted[key] = {};
} else {
key = paths[0] + "." + int;
flatted[key] = {};
}
var newKeys = Object.keys(flatted);
for (var j = 0; j < newKeys.length; j++) {
var omg = newKeys[j];
if (omg.indexOf(key) != -1 && omg.length > key.length) {
delete flatted[key];
}
}
}
}
})
console.log(flatted)
var output = unflatten(flatted);
alert(JSON.stringify(output))

how to recursively loop inside object

How to get all the values of the object and compare
Object :
obj = {
a : 10,
b : [{b1 : 101 , b2:201},{b3 : 102 , b4:204}],
c : [{c1 : 107 , c2:209 ,d :[{d1:109},{d2:402}]}]
}
function compareValues(101,obj) {
if (retriveValueFromObject(obj,101)) {
return true;
} else {
return false;
}
function comparator(a, b) {
return ('' + a).toLowerCase().indexOf(('' + b).toLowerCase()) > -1;
}
}
Pending :
retriveValueFromObject() need to be implemented such a way that i will loop in to all the key value pair of the object and send back flag(t/f) if value is in the object.
You could try something like this:
function retriveValueFromObject(theObject, value) {
for(var prop in theObject) {
if(theObject[prop] == value) {
return true;
}
if(theObject[prop] instanceof Object || theObject[prop] instanceof Array)
return getObject(theObject[prop]);
}
return false;
}
I found this here : https://stackoverflow.com/a/15524326/1062711
try:
function retrieveValueFromObject(obj,101) {
var result;
for (var key in obj){
if (typeof(obj[key]) !== 'Object')
result = comperator(101, obj[key]);
else
result = retrieveValueFromObject(obj[key],101);
}
return result;
}
didn't get to test it myself, though.
I would suggest to retrieve all values from object recursively into array and then check with Array.prototype.indexOf():
function getValues(obj) {
var result = [];
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
var curVal = obj[key];
if (typeof (curVal) === 'object') {
result = result.concat(getValues(curVal));
} else {
result.push(curVal);
}
}
}
return result;
}
console.log(getValues(o));
console.log(getValues(o).indexOf(101) !== -1);
console.log(getValues(o).indexOf('nosuchvalue') !== -1);
Fiddle

Easy way to get multi-level javascript object property

I always need to deal with multi-level js objects where existence of properties are not certain:
try { value1 = obj.a.b.c; } catch(e) { value1 = 1; }
try { value2 = obj.d.e.f; } catch(e) { value2 = 2; }
......
Is there an easier way or a generic function (e.g. ifnull(obj.d.e.f, 2) ) that does not require a lot of try catches?
var value1 = (obj.a && obj.a.b && obj.a.b.c) || 1;
http://jsfiddle.net/DerekL/UfJEQ/
Or use this:
function ifNull(obj, key, defVal){
var keys = key.split("."), value;
for(var i = 0; i < keys.length; i++){
if(typeof obj[keys[i]] !== "undefined"){
value = obj = obj[keys[i]];
}else{
return defVal;
}
}
return value;
}
var value1 = ifNull(obj, "a.b.c", 1);
You could always create a helper function.
function isUndefined(root, path, defaultVal) {
var parts = path.split('.'),
i = 0,
len = parts.length,
o = root || {}, v;
while ((typeof (v = o[parts[i]]) === 'object', o = v) && ++i < len);
return (typeof v === 'undefined' || i !== len)? defaultVal: v;
}
var obj = {a: { b: { test: 'test' }}}, v;
v = isUndefined(obj, 'a.b.test', 1); //test
v = isUndefined(obj, 'a.test', 1); //1
Using lodash you can do this easily**(node exists and empty check for that node)**..
var lodash = require('lodash-contrib');
function invalidateRequest(obj, param) {
var valid = true;
param.forEach(function(val) {
if(!lodash.hasPath(obj, val)) {
valid = false;
} else {
if(lodash.getPath(obj, val) == null || lodash.getPath(obj, val) == undefined || lodash.getPath(obj, val) == '') {
valid = false;
}
}
});
return valid;
}
Usage:
leaveDetails = {
"startDay": 1414998000000,
"endDay": 1415084400000,
"test": { "test1" : 1234 }
};
var validate;
validate = invalidateRequest(leaveDetails, ['startDay', 'endDay', 'test.test1']);
it will return boolean.

Search object with namespace / key

I'm trying to write a function that can look up a namespace and value in a JavaScript object and return the key.
Image this data:
var o = {
map: {
lat : -33.86749,
lng : 151.20699,
zoom : 12
},
filters : {
animals : {
dogs: {
myDog : 'fido'
}
}
}
};
function get(namespace, key){
//TODO
}
get('filters.animals.dogs', 'myDog')
How would you build a function that does this dynamically - no matter the depth of the namespace?
This function is somewhat close, only it modifies the original object which we don't want ofcourse:
var get = function(obj, namespace, key, value) {
var parts = namespace.split('.');
for(var i = 0; i < parts.length; i++) {
if(typeof obj[parts[i]] == 'undefined'){
obj[parts[i]] = {};
}
obj = obj[parts[i]];
}
return obj[key] = value;
};
Reason for the madness is that I cannot expose the object. It must remain private and a public method must spit out a result.
Give this a try.
function get(namespace, key) {
var parts = namespace.split('.'),
i = 0,
l = parts.length,
obj = o;
while ( i < l ) {
obj = obj[parts[i]];
if ( ! obj ) break;
i++;
}
return obj && obj[key] ? obj[key] : null;
}
I have created a fiddle with working code. Hope that helps.
http://jsfiddle.net/RdhJF/2/
var o = {
map: {
lat : -33.86749,
lng : 151.20699,
zoom : 12
},
filters : {
animals : {
dogs: {
myDog : 'fido'
}
}
}
};
function get(obj, namespace)
{
var parts = namespace.split('.');
if(parts.length==0)
return -1;
var previousValue = obj;
for(var i = 0; i < parts.length; i++)
{
if(typeof previousValue[parts[i]] == 'undefined')
return -1;
else
previousValue = previousValue[parts[i]];
}
return previousValue;
}
var myValue= get(o,'filters.animals.dogs.myDog');
alert(myValue);

Categories