Nested object and array destructuring - javascript

I am trying to convert an object to a leaner version using destructuring.
My object includes a nested array which also contains objects, from this array I would only like a few fields.
I can do the nested object destructuring fine, and the array destructuring fine but not together?
My current try looks like this:
var data = {
title: "title1",
bar: "asdf",
innerData: [
{
title: "inner-title1",
foo: "asdf"
},
{
title: "inner-title2",
foo: "asdf"
}
]
};
var { title, innerData: [ { title} ] } = data;
console.log(title);
for (var { title} of innerData) {
console.log(title);
}
But get a message saying innerData is not defined.
The outcome I would like might be:
{
title: "title1",
innerData: [
{
title: "inner-title1"
},
{
title: "inner-title2"
}
]
};

You can adjust the variable name to an identifier other than defined innerData ; use .map() or JSON.stringify(), JSON.parse() to filter title property from innerData objects
var {title, titles = data.innerData.map(o => ({title:o.title}))} = data;
to maintain innerData variable name you can use array destructuring of object
var [title, innerData] = [data.title, data.innerData.map(o => ({title:o.title}))];
using JSON.stringify(), JSON.parse()
var [title, innerData] = JSON.parse(JSON.stringify([data.title, data.innerData], ["title"]));
Edit
If requirement is to create an array containing all title properties within data you can use JSON.stringify() with replacer array set to ["title"], JSON.parse(), spread element
var data = {
title: "title1",
bar: "asdf",
innerData: [
{
title: "inner-title1",
foo: "asdf"
},
{
title: "inner-title2",
foo: "asdf"
}
]
};
var innerData = JSON.parse(JSON.stringify([data, ...data.innerData], ["title"]))
console.log(innerData);

Your destructuring doesn't do what you think.
var { title, innerData: [ { title} ] } = data;
is (essentially) equivalent to
var title = data.title;
var title = data.innerData[0].title;
Destructuring pulls out individual values, it will not map through the array for you. You'll need to do that manually if that is what you want.

As per #loganfsmyth suggested, I will do it in two steps.
var { title } = data;
for (var { title } of data.innerData) {
console.log( title );
}
Edit: my final solution to build a new json object from the old
const request = { innerData: [] };
({ title } = this.data);
for (const { title} of this.data.innerData) {
request.innerData.push({
title
});
}

Related

Add unique generated Identifier on array of json object

How to add uniqueId field in below JSON. This array has large number of data and needs to dynamic unique identifier on existing array.
[{"title":"Accompanying"},{"title":"Chamber music"},{"title":"Church
music"}......]
so, this should look as follow:
[{"title":"Accompanying", "uniqueId": 1},{"title":"Chamber music", "uniqueId": 2}..]
uniqueId- type, number or guid.
Note: don't know the "title" or what other fields could be, so, could not map the fields by name.
I would go for a simple for loop
let myArray = [{"title":"Accompanying"},{"title":"Chamber music"},{"title":"Church music"}];
let i = 0, ln = myArray.length;
for (i;i<ln;i++){
myArray[i].uniqueId = i+1;
}
console.log(myArray);
If this is a one time thing you could do the following:
const newArray = oldArray.map((x, i) => ({
// If the object is dynamic you can spread it out here and add the ID
...x,
// Use the items index in the array as a unique key
uniqueId: i,
}));
If you want to use a guid generator instead (I'd recommend that) just replace i with whatever you use to generate a GUID and ensure that any time you add to the collection you generate a new GUID for the data.
const newArray = oldArray.map((x) => ({ ...x, uniqueId: generateGuid() }));
const yourDynamicObjects = [
{
title: 'A title',
author: 'A. Author'
},
{
foo: 'bar',
},
{
quotient: 2,
irrational: Math.sqrt(2)
}
];
const updatedData = yourDynamicObjects.map((x, i) => ({ ...x, uniqueId: i, }));
console.log(updatedData);
You can use map & in it's call back function use the index parameter to create uniqueId
item.title is not known actually as its dynamic array and so, could
not map with particular field names
In this case use Object.keys to get an array of all the keys . Then loop over it and add the key to a new object
let k = [{
"title": "Accompanying"
}, {
"title": "Chamber music"
}, {
"title": "Church"
}]
let getArrayKey = Object.keys(k[0]);
let n = k.map(function(item, index) {
let obj = {};
getArrayKey.forEach(function(elem) {
obj[elem] = item[elem];
})
obj.uniqueId = index + 1
return obj;
});
console.log(n)
Also you can use spread operator
let k = [{
"title": "Accompanying"
}, {
"title": "Chamber music"
}, {
"title": "Church"
}]
let n = k.map(function(item, index) {
return Object.assign({}, { ...item,
uniqueId: index + 1
})
});
console.log(n)

How to add attribute to the root of JSON object consists of array of objects?

How to add attribute to the root of JSON object consists of array of objects?
If my JSON object something like that:
[
{
"Id":"f2ac41c5-b214-48f6-ad40-9fc35c1aaad9",
"Name":"W",
"NumberOfWorkHours":8,
"NumberOfShortDays":1,
"WorkTimeRegulationId":"f5833075-2847-4cc3-834d-6138dd0dcd99"
},
{
"Id":"5c267601-fcf2-4735-9e49-b4def3981648",
"Name":"S",
"NumberOfWorkHours":6,
"NumberOfShortDays":0,
"WorkTimeRegulationId":"8d14580e-278f-41d1-9239-8874be792580"
}
]
I do the following:
worktimeJSON.Id = $('.Js-WorkTime-id').val();
worktimeJSON.Name = $('.Js-WorkTime-name').val();
worktimeJSON.NumberOfAvailableRotations = $('.Js-WorkTime-rotations').val();
And make sure that the jQuery fetching data from the inputs but this doesn't work.
This will change property of all object in array if you want to change in particular then use index for this for exp->
worktimeJSON[0].Id = $('.Js-WorkTime-id').val();
worktimeJSON[0].Name = $('.Js-WorkTime-name').val();
worktimeJSON[0].NumberOfAvailableRotations = $('.Js-WorkTime-rotations').val();
var worktimeJSON = [
{
"Id":"f2ac41c5-b214-48f6-ad40-9fc35c1aaad9",
"Name":"W",
"NumberOfWorkHours":8,
"NumberOfShortDays":1,
"WorkTimeRegulationId":"f5833075-2847-4cc3-834d-6138dd0dcd99"
},
{
"Id":"5c267601-fcf2-4735-9e49-b4def3981648",
"Name":"S",
"NumberOfWorkHours":6,
"NumberOfShortDays":0,
"WorkTimeRegulationId":"8d14580e-278f-41d1-9239-8874be792580"
}
];
worktimeJSON = worktimeJSON.map(function(val){
val.Id = $('.Js-WorkTime-id').val();
val.Name = $('.Js-WorkTime-name').val();
val.NumberOfAvailableRotations = $('.Js-WorkTime-rotations').val();
return val;
});
Push can do the job.
let worktimeJSON = [
{
"Id":"f2ac41c5-b214-48f6-ad40-9fc35c1aaad9",
"Name":"W",
"NumberOfWorkHours":8,
"NumberOfShortDays":1,
"WorkTimeRegulationId":"f5833075-2847-4cc3-834d-6138dd0dcd99"
},
{
"Id":"5c267601-fcf2-4735-9e49-b4def3981648",
"Name":"S",
"NumberOfWorkHours":6,
"NumberOfShortDays":0,
"WorkTimeRegulationId":"8d14580e-278f-41d1-9239-8874be792580"
}
];
worktimeJSON.push
({
id: "someID",
name: "toto",
WorkTimeRegulationId: 42
});
console.log(worktimeJSON);
I structure my object like this:
let WorkTimeRegulationViewModelJSON = {
Id: $('.Js-WorkTimeRegulation-id').val(),
Name: $('.Js-WorkTimeRegulation-name').val(),
NumberOfAvailableRotations: $('.Js-WorkTimeRegulation-rotations').val(),
AssignedWorkTimes: JSON.parse(worktimeJSON)
};

How to access other object sibling's value?

I'm just wondering if it's possible to refer to self (object) value inside the object sibling like below?
[
{
"name": "Zulh",
"name_uppercase": uppercase(self.name) // expects ZULH
},
{
"name": "John",
"name_uppercase": uppercase(self.name) // expects JOHN
}
]
Note:
Code for uppercase is omitted for brevity. In my real code, it's doing synchronous complex stuff and is not actually simple string case manipulation like that.
Using a GETTER
If you want to keep it dynamic and make it work even if you change the name property, you can use a GETTER to do this kind of thing:
const names = [
{
"name": "John",
get name_uppercase() {
return this.name.toUpperCase();
}
}
]
console.log(names[0].name_uppercase)
GETTER for multiple objects
You don't have to write this for every property manually! Use .forEach:
const names = [
{
"name": "John"
},
{
"name": "Mike"
}
]
names.forEach(object => {
Object.defineProperty(object, 'nameUppercase', {
get: function() { return this.name.toUpperCase() }
});
});
console.log(names[0].nameUppercase)
console.log(names[1].nameUppercase)
Using a class and a GETTER
Or as #Rajesh pointed out you can use a class instead:
class Person {
constructor(name) {
this.name = name;
}
get nameUpperCase() {
return this.name.toUpperCase();
}
}
const names = [ new Person("John"), new Person("Mike")];
console.log(names[0].nameUpperCase);
console.log(names[1].nameUpperCase);
You can't reference an object during initialization when using object literal syntax.. Inshort, that's not possible what you expect above
Well, you can use map and add additional/modified properties to you object like
data.map(o=> ({name: o.name, upper_case : o.name.toUpperCase()}))
var data = [
{
"name": "Zulh"
},
{
"name": "John"
}
];
var x = data.map(o=> ({name: o.name, upper_case : o.name.toUpperCase()}))
console.log(x)
You can use Array.forEach and update the objects in Array
var data = [{"name": "Zulh"},{"name": "John"}];
data.forEach(o=> o.upper_case = o.name.toUpperCase());
console.log(data);
Why not create a function that transforms your incoming array? A way to do it could be like this:
const value = [
{
"name": "Zulh"
},
{
"name": "John"
}
];
const transform = ( array, propertyToUpdate, propertyToCreate, transformation ) => {
return array.map( item => ({ ...item, [propertyToCreate]: transformation( item[propertyToUpdate] ) }) );
};
console.log( transform( value, 'name', 'name_uppercase', ( item ) => item.toUpperCase() ) );
You can't do this with the object literal syntax, since it's 'this' property will not be set at that time. For example, if you'd run your code in the browser, 'this' would refer to the window object.
So you'll either have to use one of the other answers or go for a 'class':
var uppercase = function( str ) {
return str.toUpperCase();
};
var Person = function( name ) {
this.name = name;
this.name_uppercase = uppercase( this.name );
};
var persons = [
new Person( 'zuhi' ),
new Person( 'john' )
];
console.log( persons );
Same can be written in ES6 class syntax.
I would suggest 2 approaches:
If you DO NOT want to change your initial array ( which is recommended ), use map which returns a new array with changed values ( calls a function for every array item ) .
See below
let arr = [
{
"name": "Zulh",
},
{
"name": "John",
}
];
const newArr = arr.map((x)=>{
x.name_uppercase = (x.name).toUpperCase()
return x
})
console.log(newArr)
If you don't mind changing your initial array, you can use forEach. Keep in mind that unlike map, forEach changes your array and so it doesn't return anything.
let arr = [
{
"name": "Zulh",
},
{
"name": "John",
}
];
arr.forEach((x)=>{
x.name_uppercase = (x.name).toUpperCase()
})
console.log(arr)
So it all depends if you want to change your current array or not
How about using a getter method?
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get
The get syntax binds an object property to a function that will be
called when that property is looked up.
foo = [
{
"name": "Zulh",
get name_uppercase () {
return (this.name).toUpperCase();
}
},
{
"name": "John",
get name_uppercase () {
return (this.name).toUpperCase();
}
}
]
console.log(foo[1].name_uppercase); //returns JOHN
Hope it helps :)

Create object from JSON using headers from JSON

I have a JSON object that is similar to below:
vehicles:
{
trucks: [
"Ford",
"Toyota",
"Dodge",
],
suvs: [
"Honda",
"GMC",
],
cars: [
"Pontiac",
"Lotus",
"Aston-Martin",
"Porsche",
"Subaru"
]
}
I would like to loop through this and create my own object, however I cannot find out how to do it without using three different loops for each type of vehicle.
Here is my attempt below:
let vehicleObject = {
vehicles: []
}
// I'm getting the response back from a http request
Object.keys(body.vehicles).forEach(function (k) {
for (let i = 0; i < body.vehicles.k.length; i++) {
vehicleObject.vehicles.push({
vehicle_type: k,
manufacturer: body.vehicles.k[i]
});
}
});
However, this just leads me to "cannot read property length of undefined. I know I can accomplish this with a switch or three if's but I would like to learn a more efficient way, if possible. Thank you.
Loop should be like this:
Object.keys(body.vehicles).forEach(function (k) {
for (let i = 0; i < body.vehicles[k].length; i++) {
vehicleObject.vehicles.push({
vehicle_type: k,
manufacturer: body.vehicles[k][i]
});
console.log(vehicles[k].length)
}
});
When you iterate over each key you are getting name of the keys in k and then to get the array from body.vehicles object you need to do something like body.vehicles[k].
To declare global variable for the scope you should probably use var instead of let
var vehicleObject = {
vehicles: []
};
let is reachable only inside {...} block, like you used it in your for {...} loop.
Looks like you want an array of objects, like:
[{ vehicle_type: 'suvs', manufacturer: 'Honda' }, ... ]
Assuming, body contains the vehicles object:
const { vehicles } = body
const vehicleTypes = Object.keys(vehicles)
const getManufacturers = type => vehicles[type]
const createVehicle = (type, mf) => ({ vehicle_type: type, manufacturer: mf })
let flattenedVehicles = []
vehicleTypes.forEach(type => {
flattenedVehicles.push(
getManufacturers(type).map(mf => createVehicle(type, mf))
)
})
// flattenedVehicles now has desired array

Reordering array objects via javascript

I have been doing some sorting and still dont get it why the result is []. could you guys help me out what im missing?
I have my raw array object:
var data = [
{message:'hello', username:'user1'},
{message:'data', username:'user1'},
{message:'sample', username:'user2'},
{message:'here', username:'user2'},
];
my function is:
var chat = [];
function reorder(obj) {
obj.forEach( function(val, i) {
if(typeof chat[val.username] === 'undefined') {
chat[val.username] = [];
chat[val.username].push(val);
}
else
chat[val.username].push(val);
});
return chat;
}
and on my console:
reorder(data);
I am expecting to have:
var data2 = [
'user1': [{message:'hello', username:'user1'}, {message:'data', username:'user1'} ],
'user2': [{message:'sample', username:'user2'}, {message:'here', username:'user2'} ],
];
You can do this easily with reduce:
var data2 = data.reduce(function(acc, x) {
acc[x.username] = (acc[x.username] || []).concat(x)
return acc
},{})
/*^
{ user1:
[ { message: 'hello', username: 'user1' },
{ message: 'data', username: 'user1' } ],
user2:
[ { message: 'sample', username: 'user2' },
{ message: 'here', username: 'user2' } ] }
*/
The problem is that you made chat an array. When you look at an array in the console, it only displays the numeric indexes, not the named properties; you have to use console.log(chat) to see the named properties.
Since you want this to be an object with named properties, you should declare it as an object, not an array:
var chat = {};
Use Underscore's _.groupBy:
_.groupBy(data, 'username')

Categories

Resources