How flatten object literal properties? - javascript

I have an object being returned by a legacy server and I want to change the structure on the client-side via JavaScript, jQuery, or even Underscore.js.
Below is what my original object looks like:
[
{
"Id":{
"LValue":1,
"Value":1
},
"Date":{
"LValue":"2013-10-17T00:00:00",
"Value":"2013-10-24T00:00:00"
},
"User":{
"LValue":508,
"Value":507
},
"Comments":{
"LValue":"This a test load",
"Value":"This a test"
},
"Name":"John Doe",
"IsDeleted":false
}
]
On the client-side though, I would like to flatten it to get the "Values" and stuff the "LValues" into a separate property so I don't loose them if I need it later:
[
{
"Id":1,
"Date":"2013-10-24T00:00:00",
"User":507,
"Comments":"This a test",
"Name":"John Doe",
"IsDeleted":false,
"LValues": {
"Id":1,
"Date":"2013-10-17T00:00:00",
"User":508,
"Comments":"This a test load"
}
}
]
this would make working with the object so much easier and any help would be deeply appreciated!

var oList = [
{
"Id":{
"LValue":1,
"Value":1
},
"Date":{
"LValue":"2013-10-17T00:00:00",
"Value":"2013-10-24T00:00:00"
},
"User":{
"LValue":508,
"Value":507
},
"Comments":{
"LValue":"This a test load",
"Value":"This a test"
},
"Name":"John Doe",
"IsDeleted":false
}
];
var newFormat = _(oList).map(function(o) {
var flattened = { LValues: {} };
_(o).each(function(val, propName) {
flattened[propName] = val.Value ? val.Value : val;
if(val.LValue) {
flattened.LValues[propName] = val.LValue;
}
});
return flattened;
}

You could use a basic Javascript map for this. Assuming hard-coded properties:
var flattenedItems = items.map(function(x) {
return {
Id: x.Id.Value,
Date: x.Date.Value,
User: x.User.Value,
Comments: x.Comments.Value,
Name: x.Name,
IsDeleted: x.IsDeleted,
LValues: {
Id: x.Id.LValue,
Date: x.Date.LValue,
User: x.User.LValue,
Comments: x.Comments.LValue,
}
};
});
(Fiddle)
If the properties are variable, then you could iterate through them inside the map iterator:
var flattenedItems = items.map(function(x) {
var flattened = { LValues: {} };
for (var prop in x) {
flattened[prop] = x[prop].Value;
flattened.LValues[prop] = x[prop].LValue;
};
return flattened;
});
(Fiddle)

You could use
var items = [
{
"Id":{
"LValue":1,
"Value":1
},
// ...
}
];
items = items[0];
var obj = {LValues: {}};
for(var i in items) {
if(typeof items[i] === 'object') {
obj[i] = items[i].Value;
obj.LValues[i] = items[i].LValue;
} else {
obj[i] = items[i];
}
}

I believe that the output is actually write a simple function
function flatten(obj){
var r = {};
if(obj){
console.log(obj);
r.Id = obj.Id.Value;
r.Date = obj.Date.Value;
r.User = obj.User.Value;
r.Comments = obj.Comments.Value;
r.Name = obj.Name.Value;
r.IsDeleted = obj.IsDeleted;
r.LValues = {};
r.LValues.Id = obj.Id.LValue;
r.LValues.Date = obj.Date.LValue;
r.LValues.User = obj.User.LValue;
r.LValues.Comments = obj.Comments.LValue;
}
return r;
}

Related

Perform .join on a complex object with array of object dynamically

I have a complex js object, that contains arrays of an object. The problem is some of the main object properties' arrays can have a different property.
var foo = {};
foo.prop1 = [
{name:"test", skill:1},
{name:"test2", skill:2},
];
foo.prop2 = [
{address:"Earth",distance:1},
{address:"Mars", distance:2}
]
My aim is to just replace the main object property value with the joined values for retrieval.
This is what I have right now.
if(Object.keys(foo).length){
Object.keys(foo).forEach(key => {
var x = foo[key];
if(key === "address") {
foo[key] = x.map(function(elem){return elem.address;}).join(";");
} else {
foo[key] = x.map(function(elem){return elem.name;}).join(";");
}
});
}
How can I make it dynamic so that I don't need to use the if statement? I just want to join all the first property of the inner obj.
Result:
foo new values would be:
foo.prop1 = test;test2
foo.prop2 = Earth;Mars
I got it. I just want to join the first property of the sub object.
I replaced the if with this
foo[key] = x.map(function(elem){return elem[Object.keys(elem)[0]]; }).join(";");
I guess you are trying to choose the value with string type
var foo = {};
foo.prop1 = [{
name: "test",
skill: 1
},
{
name: "test2",
skill: 2
},
];
foo.prop2 = [{
address: "Earth",
distance: 1
},
{
address: "Mars",
distance: 2
}
]
function formulate() {
const result = {};
(Object.keys(foo) || []).forEach(function(k) {
result[k] = foo[k].map(function(val) {
str_key = Object.keys(val).filter(function(val_k) {
return typeof val[val_k] === "string";
});
return str_key.map(function(s) {
return val[s];
});
}).join(";");
});
return result;
}
result = formulate()
console.log(result);
I hope, this will work for you
var foo = {};
foo.prop1 = [
{name:"test", skill:1},
{name:"test2", skill:2},
];
foo.prop2 = [
{address:"Earth",distance:1},
{address:"Mars", distance:2}
]
Object.keys(foo).forEach(key => {
foo[key]=foo[key].map(val => { return Object.entries(val)[0][1] } ).toString().split(",").join(";")
});
console.log(foo)

Setting a deep JS object key using a lookup string

How do I set deep properties in a JavaScript object using a dot-syntax string to specify which property I want to change?
For simple objects, I could just use data['property_name'] = 'foo', but I don't necessarily know how deeply nested the data is going to be.
Below is some example code with how I'd like to be able to format the data in the end. For all I know there's a nice way that JS already allows you to do this, but I haven't been able to find it yet.
Plunker here.
var items = [
{
lookup_string: "User.UserProfile.name",
value: "John Smith"
},
{
lookup_string: "User.email",
value: "johnsmith#example.com"
},
]
var data = {};
items.forEach(function(item){
// Inside this loop, set the appropriate keys under data. Is there a non-convoluted way to do this?
});
console.log("items", items);
console.log("Results", data)
// In the end, data should look like this:
var desiredData = {
User: {
UserProfile: {
name: 'John Smith'
},
email: 'johnsmith#example.com'
}
}
You could split the lookup_string and reduce an object with a default object. Later assign the value.
function setValue(object, path, value) {
var keys = path.split('.'),
last = keys.pop();
keys.reduce(function (o, k) {
return o[k] = o[k] || {};
}, object)[last] = value;
}
var items = [{ lookup_string: "User.UserProfile.name", value: "John Smith" }, { lookup_string: "User.email", value: "johnsmith#example.com" }],
object = {};
items.forEach(function(o) {
setValue(object, o.lookup_string, o.value);
});
console.log(object);
.as-console-wrapper { max-height: 100% !important; top: 0; }
you will have to loop over all the keys from lookup_string.split('.') and assign values, something like this:
var items = [
{
lookup_string: "User.UserProfile.name",
value: "John Smith"
},
{
lookup_string: "User.email",
value: "johnsmith#example.com"
},
];
var data = {};
items.forEach(function(item){
var lookup = item.lookup_string.split('.');
var lastKey;
lookup.map(function(key){
data[key] = {};
lastKey = key;
});
data[lastKey] = item.value;
});
console.log("items", items);
console.log("Results", data)
// In the end, data should look like this:
var desiredData = {
User: {
UserProfile: {
name: 'John Smith'
},
email: 'johnsmith#example.com'
}
};

Compare 2 arrays in javascript and extract differences

Array 1 is the result of the data from a localstorage
Array 2 is, for the same IDs (329, 307, 355), the result after treatment
So i need to compare both to notify what changed
Array 1 :
[{"329":["45738","45737","45736"]},{"307":["45467","45468"]},{"355":["47921"]}]
Array 2 :
[{"355":["47921","45922"]},{"329":["45738","45737","45736"]},{"307":[]}]
I need to compare Array 2 with Array 1 and extract differences.
In this example i want to have for result
[{"355":["45922"]},{"307":[]}]
I try to adapt this code :
var compareJSON = function(obj1, obj2) {
var ret = {};
for(var i in obj2) {
if(!obj1.hasOwnProperty(i) || obj2[i] !== obj1[i]) {
ret[i] = obj2[i];
}
}
return ret;
};
Runnable:
var array1 = [{
"329": ["45738", "45737", "45736"]
}, {
"307": ["45467", "45468"]
}, {
"355": ["47921"]
}],
array2 = [{
"355": ["47921", "45922"]
}, {
"329": ["45738", "45737", "45736"]
}, {
"307": []
}]
var compareJSON = function(obj1, obj2) {
var ret = {};
for (var i in obj2) {
if (!obj1.hasOwnProperty(i) || obj2[i] !== obj1[i]) {
ret[i] = obj2[i];
}
}
return ret;
};
console.log(compareJSON(array1, array2));
But, either I have nothing or I have the whole table
your requirement(result) is not clear, but this will get you started.
var arr1 = [{ "329": ["45738", "45737", "45736"] }, { "307": ["45467", "45468"] }, { "355": ["47921"] }],
arr2 = [{ "355": ["47921", "45922"] }, { "329": ["45738", "45737", "45736"] }, { "307": [] }];
var result = [];
arr2.forEach(obj => {
var key = Object.keys(obj)[0];
var match = arr1.find(o => o.hasOwnProperty(key));
if (match) {
var newObj = {};
newObj[key] = obj[key].filter(s => match[key].indexOf(s) === -1);
if (!obj[key].length || newObj[key].length) result.push(newObj)
} else {
result.push(Object.assign({}, obj));
}
});
console.log(result);
You could use a hash tbale and delete found items. If some items remains, then an empty array is taken to the result object.
var array1 = [{ 329: ["45738", "45737", "45736"] }, { 307: ["45467", "45468"] }, { 355: ["47921"] }],
array2 = [{ 355: ["47921", "45922"] }, { 329: ["45738", "45737", "45736"] }, { 307: [] }],
hash = {},
result = [];
array1.forEach(function (o) {
Object.keys(o).forEach(function (k) {
hash[k] = hash[k] || {};
o[k].forEach(function (a) {
hash[k][a] = true;
});
});
});
array2.forEach(function (o) {
var tempObject = {};
Object.keys(o).forEach(function (k) {
var tempArray = [];
o[k].forEach(function (a) {
if (hash[k][a]) {
delete hash[k][a];
} else {
tempArray.push(a);
}
});
if (tempArray.length || Object.keys(hash[k]).length) {
tempObject[k] = tempArray;
}
});
Object.keys(tempObject).length && result.push(tempObject);
});
console.log(result);
I've used the deep-diff package in npm for this sort of thing before:
It may be more detail than you want though - here's an example from the readme of the output format:
[ { kind: 'E',
path: [ 'name' ],
lhs: 'my object',
rhs: 'updated object' },
{ kind: 'E',
path: [ 'details', 'with', 2 ],
lhs: 'elements',
rhs: 'more' },
{ kind: 'A',
path: [ 'details', 'with' ],
index: 3,
item: { kind: 'N', rhs: 'elements' } },
{ kind: 'A',
path: [ 'details', 'with' ],
index: 4,
item: { kind: 'N', rhs: { than: 'before' } } } ]
Checkout the readme on the github page linked above for details about what it all means, or try it out for yourself online using runkit
But in order for this to work you would have to do some sort of preprocessing:
Sort array based on first key of each element:
a1 = a1.sort((lhs, rhs) => {
return parseInt(Object.keys(lhs)[0]) - parseInt(Object.keys(rhs)[0]);
})
If you sort both of the arrays by the first key of each element and then pass it to the diff tool, you get the following:
[
{"kind":"A","path":[0,"307"],"index":0,"item":{"kind":"D","lhs":"45467"}},
{"kind":"A","path":[0,"307"],"index":1,"item":{"kind":"D","lhs":"45468"}},
{"kind":"A","path":[2,"355"],"index":1,"item":{"kind":"N","rhs":"45922"}}
]
If it were me I would probably merge all the array elements and diff the resulting object so you completely avoid any object order and duplicate key issues.
Alternative: merge array contents into one object
A naive merge might look like this:
a1Object = {}
a1.forEach((element) => {
Object.keys(element).forEach((key) => {
a1Object[key] = element[key];
});
})
Which produces the following diff:
[
{"kind":"A","path":["307"],"index":0,"item":{"kind":"D","lhs":"45467"}},
{"kind":"A","path":["307"],"index":1,"item":{"kind":"D","lhs":"45468"}},
{"kind":"A","path":["355"],"index":1,"item":{"kind":"N","rhs":"45922"}}
]
Interpreting the diff output
there is a change in the Array value of 307 at index 0: 45467 has been Deleted
there is a change in the Array value of 307 at index 1: 45468 has been Deleted
there is a change in the Array value of 355 at index 1: 45467 has been Newly added

Cleaning up a JSON object that is full of objects with 1 attribute

I have a JSON object that's formatted like the following:
{
"ATTR1": {
"0":"Value1"
},
"ATTR2": {
"0":"Value2"
} //and so on
}
and this format holds for dozens of attributes. I'm looking for a way to have the JSON be more like:
{
"ATTR1": "Value1",
"ATTR2": "Value2" //and so on
}
Is there an easy way to do this in Javascript? I've tried something like:
for(var attr in obj) {
if(obj.hasOwnProperty(attr)) {
attr = attr[0];
}
}
But this hasn't been working. Any ideas?
Use reduce on the object's keys for that:
let foo = {
"ATTR1": {
"0":"Value1"
},
"ATTR2": {
"0":"Value2"
} //and so on
};
let res = Object.keys(foo).reduce((a,b) => {
a[b] = foo[b]['0'];
return a;
}, {});
console.log(res)
If you want to mutate the original obj, you can do this:
for(var attr in obj) {
if(obj.hasOwnProperty(attr)) {
obj[attr] = obj[attr][0];
}
}
you are close!
Try something like this:
var obj = {
"ATTR1": {
"0":"Value1"
},
"ATTR2": {
"0":"Value2"
} //and so on
};
var obj2 = {};
for(var attr in obj) {
if(obj.hasOwnProperty(attr)) {
obj2[attr] = obj[attr][0];
}
}
alert(JSON.stringify(obj2));
Fiddle: https://jsfiddle.net/coLxfeum/
Iterating over javascript objects is easier using Object.keys(), IMO. It's supported in the major browsers... Anyway, you want to iterate over the top level object, grabbing all of it's "smallObject" values and flatten them. You can make the checks as strict as you like (insisting on "0" keys etc), but fundamentally, it seems important that the values you are collapsing are single-value objects containing string values? Anyway - here's how you could do that:
var v1 = {
"ATTR1": {
"0": "Value1"
},
"ATTR2": {
"0": "Value2"
}
}
function flatten(obj) {
Object.keys(obj).forEach( function(attr) {
var smallObj = obj[attr];
var keys = Object.keys(smallObj);
if( keys.length === 1 && typeof smallObj[keys[0]] === 'string' ) { // && keys[0] === "0" ?
obj[attr] = smallObj[keys[0]];
} // else throw Error(...) ?
})
return obj;
}
console.log(flatten(v1));
> { ATTR1: 'Value1', ATTR2: 'Value2' }
Try this :
var jsonObj = {
"ATTR1": {
"0":"Value1"
},
"ATTR2": {
"0":"Value2"
}
};
var newJson = {};
for(var i = 0;i<Object.keys(jsonObj).length;i++) {
newJson[Object.keys(jsonObj)[i]] = jsonObj[Object.keys(jsonObj)[i]]["0"];
}
console.log(newJson);

How to insert objects through javascript?

I have stored group of objects into one array called 'resData' and i'm having one more array of data called 'approvedIds', there have included all approved id's. Here i want to match these two arrays and add one new key into 'resData' array like 'approveStatus:"approve"'. How to do this one in javascript?
All data's,
var resData = [
{
firstName:"Jhon",
lastName:"adam",
emailId:"jhn12#gmail.com",
id:"01"
},
{
firstName:"Kyle",
lastName:"Miller",
emailId:"kl12#gmail.com",
id:"02"
},
{
firstName:"Jhonathan",
lastName:"adam",
emailId:"jadm12#gmail.com",
id:"03"
},
{
firstName:"Lewis",
lastName:"harber",
emailId:"lewh12#gmail.com",
id:"04"
}
];
Approved id's array,
var approvedIds = ['01', '03'];
My output will be like this,
var resData = [
{
firstName:"Jhon",
lastName:"adam",
emailId:"jhn12#gmail.com",
id:"01",
approveStatus:'approved'
},
{
firstName:"Kyle",
lastName:"Miller",
emailId:"kl12#gmail.com",
id:"02"
},
{
firstName:"Jhonathan",
lastName:"adam",
emailId:"jadm12#gmail.com",
id:"03",
approveStatus:'approved'
},
{
firstName:"Lewis",
lastName:"harber",
emailId:"lewh12#gmail.com",
id:"04"
}
];
You can try this. Use forEach and indexOf functions
var resData = [
{
firstName:"Jhon",
lastName:"adam",
emailId:"jhn12#gmail.com",
id:"01"
},
{
firstName:"Kyle",
lastName:"Miller",
emailId:"kl12#gmail.com",
id:"02"
},
{
firstName:"Jhonathan",
lastName:"adam",
emailId:"jadm12#gmail.com",
id:"03"
},
{
firstName:"Lewis",
lastName:"harber",
emailId:"lewh12#gmail.com",
id:"04"
}
];
var approvedIds = ['01', '03'];
resData.forEach(item => {
if(approvedIds.indexOf(item.id) !== -1){
item.approvedStatus = 'approved';
}
} );
console.log(resData);
Using ES6 array functions, which is more functional and doesn't alter the original objects:
var resData = [
{
firstName:"Jhon",
lastName:"adam",
emailId:"jhn12#gmail.com",
id:"01"
},
{
firstName:"Kyle",
lastName:"Miller",
emailId:"kl12#gmail.com",
id:"02"
},
{
firstName:"Jhonathan",
lastName:"adam",
emailId:"jadm12#gmail.com",
id:"03"
},
{
firstName:"Lewis",
lastName:"harber",
emailId:"lewh12#gmail.com",
id:"04"
}
];
var approvedIds = ['01', '03'];
//Solution:
var newData = resData
.filter(rd => approvedIds.indexOf(rd.id) >= 0)
.map(rd => Object.assign({}, rd, {approvedStatus: "approved"}));
console.log(newData, resData);

Categories