Recursively manipulate javascript object data ends - javascript

Is there a way to walk through an arbitrary Javascript object, and alter it at its data ends, wherever its not another nested object?
So given the below, could I log an object where '123', 'bar', 'die', 'or' become 'xyz'?
var jso = {
hello:[
{ foo:'bar' },
{ abc: { def:'123' } }
],
world:[
{ ride:['or','die'] }
]
};
function recurse(object) {
if (Object.prototype.toString.call(object) === '[object Array]') {
var l = object.length;
while(l--){
recurse(object[l])
}
} else if(typeof object === 'object') {
for(var key in object) {
recurse(object[key])
}
} else {
object = 'xyz';
}
}
recurse(jso)
console.log(jso)

object = 'xyz';
That won't work, as it just changes the object variable that is local to the function call. To actually modify an object, you need to assign to a property:
function recurse(object) {
if(Object.prototype.toString.call(object) === '[object Array]'){
for (var l = object.length; l--; ) {
if (typeof object[l] == 'object')
recurse(object[l]);
else
object[l] = 'xyz';
}
} else {
for(var key in object) {
if (typeof object[key] == 'object')
recurse(object[key]);
else
object[key] = 'xyz';
}
}
}
or (better)
function recurse(object) {
if (typeof object !== 'object')
return 'xyz';
if (Object.prototype.toString.call(object) === '[object Array]'){
for (var l = object.length; l--; ) {
object[l] = recurse(object[l]);
}
} else {
for (var key in object) {
object[key] = recurse(object[key])
}
}
return object;
}

Object.keys is nice in these situations.
function recurse(datum) {
if (Array.isArray(datum)) {
datum.forEach(function (arrayItem, idx) {
datum[idx] = recurse(datum[idx]);
});
return datum;
} else if (typeof datum === 'object') {
Object.keys(datum).forEach(function (key) {
datum[key] = recurse(datum[key]);
});
return datum;
} else {
return 'xyz';
}
}
JSFiddle

Nice and simple:
function recurse(object) {
Object.keys(object).forEach(function(key) {
if (typeof object[key] == "object") {
recurse(object[key]);
} else {
object[key] = "xyz";
}
});
}

Related

Get value of symbol defined inside object literal and iterate over its values

I have an object literal like below.
{
is_active: true,
start_date: { [Symbol(lt)]: 2020-02-24T12:56:36.780Z },
expiry_date: { [Symbol(gt)]: 2020-02-24T12:56:36.780Z },
[Symbol(or)]: [ { user_id: 'M' }, { user_id: null } ]
}
These objects are automatically generated by sequelize before querying to database
I need to iterate through all object keys and change the value of that key which is id or ends with _id.
This is my first time with Symbol datatype. I read a article here, It says they can't be iterate using for...in or object...keys
I also read an answer here, but It only said how to access it.
Below is my function that iterate recursively though the object and decrypts id and value of keys ending with _id
function decryptIds(obj) {
if (typeof obj === 'object' && obj !== null) {
for (let key in obj) {
if (Array.isArray(obj[key])) {
for(let i = 0; i< obj[key].length; i++) {
if(typeof obj[key][i] === 'object' && obj[key][i] !==null)
decryptIds(obj[key][i].where)
else
obj[key][i] = decrypt(obj[key][i])
}
} else if (typeof obj[key] === 'object' && obj !== null) {
decryptIds(obj[key].where)
}
else if (key === 'id' || key.endsWith('_id')) {
obj[key] = decrypt(obj[key])
}
}
}
return
}
decryptIds(model.where)
Somehow, I managed to do it. I know it's not the solution, it's easily feasible. I will keep try until I get any better approach. For now it is okay.
beforeFind: (model, options) => {
function decryptIds(obj) {
if(typeof obj === 'object' && obj!==snull &&Object.getOwnPropertySymbols(obj)) {
const objectSymbols = obj[Object.getOwnPropertySymbols(obj)[0]]
if(objectSymbols) {
objectSymbols.forEach(el => {
decryptIds(el)
})
}
}
if (typeof obj === 'object' && obj !== null) {
for (let key in obj) {
if (Array.isArray(obj[key])) {
for(let i = 0; i< obj[key].length; i++) {
if(typeof obj[key][i] === 'object' && obj[key][i] !==null)
decryptIds(obj[key][i].where)
else
obj[key][i] = decrypt(obj[key][i])
}
}
else if (key === 'id' || key.endsWith('_id')) {
if(obj[key]) {
obj[key] = decrypt(obj[key])
}
} else if (typeof obj[key] === 'object' && obj !== null) {
decryptIds(obj[key].where)
}
}
}
return
}
console.log(model.where)
decryptIds(model.where)
console.log(model.where)
},

How can I create empty JSON keys (nested or not) using a string?

I currently have this code built in JS, but it's really, really ugly.
Is there any better way to approach it?
The way it works basically is pushing a string like app.chat.test to be the key, and value like teststr.
I test the lengths to see if the "parent" key is there, otherwise we build it.
function constructJson(jsonKey, jsonValue){
//REWRITE!!!!!!!!
let jsonObj = langFile;
let jsonKeyArr = jsonKey.split('.')
if (jsonKeyArr.length === 1) {
if (valToAdd === undefined) {
if (jsonObj[jsonKey] === undefined) {
jsonObj[jsonKey] = {}
}
} else {
if (jsonObj[jsonKey] === undefined) {
jsonObj[jsonKey] = valToAdd
}
}
} else if (jsonKeyArr.length === 2) {
if (jsonObj[jsonKeyArr[0]] === undefined) {
jsonObj[jsonKeyArr[0]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] = jsonValue
}
} else if (jsonKeyArr.length === 3) {
if (jsonObj[jsonKeyArr[0]] === undefined) {
jsonObj[jsonKeyArr[0]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]] = jsonValue
}
} else if (jsonKeyArr.length === 4) {
if (jsonObj[jsonKeyArr[0]] === undefined) {
jsonObj[jsonKeyArr[0]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]][jsonKeyArr[3]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]][jsonKeyArr[3]] = jsonValue
}
} else if (jsonKeyArr.length === 5) {
if (jsonObj[jsonKeyArr[0]] === undefined) {
jsonObj[jsonKeyArr[0]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]][jsonKeyArr[3]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]][jsonKeyArr[3]] = {}
}
if (jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]][jsonKeyArr[3]][jsonKeyArr[4]] === undefined) {
jsonObj[jsonKeyArr[0]][jsonKeyArr[1]][jsonKeyArr[2]][jsonKeyArr[3]][jsonKeyArr[4]] = jsonValue
}
} else if (jsonKeyArr.length > 5) {
return console.log("Length over 5 not supported yet!")
}
return jsonObj;
}
Regards.
OF course it's possible, a simple loop will perfeclty do the job.
function constructJson(jsonKey, jsonValue){
//REWRITE!!!!!!!!
langFile = {a:{}, foo:{}};// remove this for your own code
var jsonObj = langFile;
var jsonKeyArr = jsonKey.split('.');
var currentValue = jsonObj;
for(var i = 0; i < jsonKeyArr.length;i++){
if(currentValue[jsonKeyArr[i]]===undefined){
currentValue[jsonKeyArr[i]] = {};
}
if(i < jsonKeyArr.length-1){
currentValue = currentValue[jsonKeyArr[i]];
}else{
currentValue[jsonKeyArr[i]] = jsonValue;
}
}
return jsonObj;
}
alert(JSON.stringify(constructJson("a.b.cd.ef", "toto")));
I just assigning to a temporary variable each sublevel. When i'm on the last i'm assigning the value.
Yes you can, using the javascript reduce function on the array created from the splitted string.
function namespaceCreateExceptLast(representationOfElementToCreate, baseNamespace) {
var tokens;
if (typeof representationOfElementToCreate !== 'string')
throw new Error('Expecting string as first parameter');
if (baseNamespace === undefined)
baseNamespace = window;
tokens = representationOfElementToCreate.split('.');
// Remove the last element (which will contain the value)
tokens.pop();
// Use reduce to create part by part your new object
return tokens.reduce(function (prev, property) {
if (typeof prev !== 'object') {
throw Error('One property is already defined but not an object, namespace creation has failed', property);
return undefined;
} else {
if (!prev[property])
prev[property] = {};
return prev[property];
}
}, baseNamespace);
};
Then you can have:
function constructJson(jsonKey, jsonValue){
let jsonObj = langFile;
var lastItem = namespaceCreateExceptLast(jsonKey, jsonObj);
var lastKey = jsonKey.substring(jsonKey.lastIndexOf('.') + 1);
lastItem[lastKey] = jsonValue;
}
I have added some comments and exceptions to help you understand how it's done, but it's mainly based on the reduce function which you can easily get help for (https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Array/reduce).

Recursive method for checking an object

So I have created a constructor that I am attempting to prototype. I want a method that checks through each property in an object to see if its empty and if it is it returns the key. If the property is an object I want it to check through that sub object as well.
UPDATED:
My code thus far:
function Properties(val1, val2, val3, val4){
this.prop1 = val1 || "";
this.prop2 = val2 || "";
this.prop3 = val3 || "";
this.prop4 = val4 || {};
}
Properties.prototype = {
isEmpty: function(){
for (key in this) {
if(typeof this[key] == "object" && this[key] !== null){
this[key].isEmpty();
} else {
if(!this[key]){
console.log(key);
}
}
}
}
}
var test = new Properties("Something", "", "", {subProp1: "Something Else", subProp2: "", subProp3: {subSubProp1: "", subSubProp2: "" }});
The method should return prop2, prop3, subProp2, subSubProp1, subSubProp2
That method isn't a property on the object. You need to pass in the object in question. You can also pass an array in to keep track of the empty keys:
var emptyKeys = [];
function isEmpty(obj, keysArr) {
for (var key in obj) {
if (typeof obj[key] === "object" && obj.hasOwnProperty(key)) {
isEmpty(obj[key], keysArr);
} else {
if (obj[key] == "" || obj[key] == null) {
keysArr.push(key);
}
}
}
}
Demo: http://jsfiddle.net/17rt0qy3/1/
If you want this on the actual object, simply add the above function inside the isEmpty function:
isEmpty: function(){
var emptyKeys = [];
amIEmpty(this, emptyKeys);
return emptyKeys;
//Actual logic
function amIEmpty(obj, keysArr) {
for (var key in obj) {
if (key == "isEmpty") {
continue;
}
if (typeof obj[key] === "object" && obj.hasOwnProperty(key)) {
amIEmpty(obj[key], keysArr);
} else {
if (obj[key] == "" || obj[key] == null) {
keysArr.push(key);
}
}
}
}
}
Demo: http://jsfiddle.net/17rt0qy3/2/
And a fiddle working with your demo object above: http://jsfiddle.net/17rt0qy3/3/
Aaand another edit, this will only log the keys, but it's a bit cleaner:
isEmpty: function(obj, keys) {
keys = keys || [];
obj = obj || this;
for (var key in obj) {
if (typeof obj[key] === "object" && obj.hasOwnProperty(key)) {
this.isEmpty(obj[key], keys)
} else {
if (obj[key] == "" || obj[key] == null) {
keys.push(key);
}
}
}
return keys;
}
Demo: http://jsfiddle.net/17rt0qy3/8/

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

Categories