How do i destructure an object - javascript

i have a function
const displayUserPhotoAndName = (data) => {
if (!data) return;
// add your code here
clearNotice();
};
After the first if(!data) return; statement that terminates the function if the expected data parameter is not provided, create a statement that de-structures the data parameter and obtains the results property from it;
Create a second statement in the next line that de-structures the results variable you just created, and obtain the first item from it (it is an Array! See https://randomuser.me/api/). Your de-structured array item should be declared as profile. This represents the profile data for the user gotten from the API call that you want to display in your app.
const displayUserPhotoAndName = (data) => {
if(!data) return;
// add your code here
const {results: results} = data;
const {profile: results} = results;
this is where i am right now but i still get an error message saying "you have not destructured the profile property from results obtained from data passed to displayUserPhotoAndName function. your assistance will be very much appreciated...

You can do this two ways:
Your approach of two steps:
const {results} = data;
const {profile} = results;
Or in one step:
const {results: {profile}} = data;
For a better understanding you should check out the documentation of object destructuring.

You can do as following if you need nth element from results array use
{ results: { n: profile } } = data;
let data = { results: [1, 2, 3, 4] }
let { results: { 0: profile1, 2: profile2 } } = data;
console.log(profile1)
console.log(profile2)
Even you can do further destructuring
let data = { results: [{ name: 'myname1', gender: 'male' }, { name: 'myname2', gender: 'male' }, { name: 'myname3', gender: 'female' }, { name: 'myname4', gender: 'male' }] }
let { results: { 0: profile1, 2: { name, gender } } } = data;
console.log(profile1)
console.log(name)
console.log(gender)

Here an example:
const data = {
results: {
name: "test1",
surname: "123"
},
profile: {
name: "test2",
surname: "321"
}
};
const { results, profile } = data;
console.log(results);
console.log("====");
console.log(profile);

Related

How to parse a property of a react object

I am working in react and have a resonse ( ReviewerService.getReviewers()) that returns an array of values:
0: {id: 1, firstName: 'John', lastName: 'Doe', email: 'johndoe#aol.com', responses: '{"q1":"yes","q2":"no","q3":"yes","rating":4}'}
1: {id: 2, firstName: 'bob', lastName: 'jefferson', email: 'bob#aol.com', responses: '{"q1":"bob","q2":"yes","q3":"yes","rating":5}'}.
If this.state = { reviewers: [] }.
How do i pass the response data into reviewers and parse the responses property at the same time? Therefore, then I can access these properties of the responses easily.
class ListReviewsComponent extends Component {
constructor(props) {
super(props);
this.state = {
reviewers: [],
};
}
async componentDidMount() {
await ReviewerService.getReviewers().then((res) => {
this.setState({ reviewers: res.data });
});
this.setState({ reviewers.responses: JSON.parse(this.state.reviewers.responses)}); // error
}
can this work
async componentDidMount() {
try {
const res = await ReviewerService.getReviewers();
// got the data
const reviewers = res.data;
// not parse the responses for each reviewer
const mappedReviewers = reviewers?.map(reviewer => {
try {
const parsedResponses = JSON.parse(reviewer.responses)
// do you need to convert parsedResponses to an array ??
return {
...reviewer,
responses: parsedResponses
}
} catch(error) {
return {
...reviewer,
responses: [] //
}
}
});
this.setState({ reviewers: mappedReviewers})
} catch (error) {
// log errors
}
}
Hope this helps you to sort out the issue
I think that you array returned by
ReviewerService.getReviewers()
should be in json format, treated or parsed, before, setted in setState:
data = [ {id: 1, firstName: 'John', lastName: 'Doe', email: 'johndoe#aol.com', responses: '{"q1":"yes","q2":"no","q3":"yes","rating":4}'}
,{id: 2, firstName: 'bob', lastName: 'jefferson', email: 'bob#aol.com', responses: '{"q1":"bob","q2":"yes","q3":"yes","rating":5}'} ];
Then you do this, putting array in a json treated object format
async componentDidMount() {
await ReviewerService.getReviewers().then((res) => {
this.setState({ reviewers: res.data });
});
When you do:
this.setState({ reviewers: res.data });
You area putting on this.state.reviewers, all list and all objects nested in.
You could access this.state on this component like this method below:
getResponsesOfReviewersOnArrayByIndex = (index) => {
return this.state.reviewers[index].responses
}
Or just in some method access,
this.state.reviewers[i].firstName
You can try this to understand better the JSON parse function:
const reviewersData = '[{"name":"neymar"}, {"name":"junior"}]';
const reviewers = JSON.parse(reviewersData);
console.log(reviewers[0].name);
In this W3Schools to see more examples of JSON.parse()
Hope this helps.

Merging values from an array of strings into a nested object in javascript

I want to merge values from an array into a static nested object. The array containing the values is something like this,
['name=ABC XYZ', 'hobbies=[M,N,O,P]', 'profession=S', 'age=27']
and the object in which the values has to be merged is,
const person = {
details_1: {
name: null,
hobbies: null,
profession: null
},
details_2: {
age: null
}
};
I want my output object to look like below,
const updated_person = {
details_1: {
name: 'ABC XYZ',
hobbies: [M,N,O,P],
profession: 'S'
},
details_2: {
age: 27
}
};
Thanks a lot for your help!
I made another solution with a different approach.
Here I used an interface weher I described the desired data structure.
In the second part the string array is tranformed into key and value pairs. Thereform are filtered the keys of interface and added into an empty object literal.
const data = ["name=ABC XYZ", "hobbies=[M,N,O,P]", "profession=S", "age=27"];
const dataInterface = {
details_1: { name: null, hobbies: null, profession: null },
details_2: { age: null },
};
function orederData(arr) {
const record = arr.map((item) => {
let [key, value] = item.split("=");
if (value[0] === "[" && value[value.length - 1] === "]") {
value = value.slice(1, value.length - 1).split(",");
}
return { key, value };
});
const dataBlock = {};
Object.keys(dataInterface).map((detail) => {
dataBlock[detail] = {};
Object.keys(dataInterface[detail]).forEach((dataKey) => {
dataBlock[detail][dataKey] = record.filter((record) => {
return record.key === dataKey;
})[0].value;
});
});
return dataBlock;
}
const orderedData = orederData(data);
console.log(orderedData);
You can simply achieve this by iterating the input array.
const arr = ['name=ABC XYZ', 'hobbies=[M,N,O,P]', 'profession=S', 'age=27'];
const person = {
details_1: {},
details_2: {}
};
arr.forEach(item => {
(item.split('=')[0] !== 'age') ? person.details_1[item.split('=')[0]] = item.split('=')[1] : person.details_2[item.split('=')[0]] = item.split('=')[1]
});
console.log(person);
There is no way to cleanly merge an unstructured array into a structured object such that the array values end up in the appropriately keyed person properties.
javascript does provide the assign() function that merges objects but for YOUR requirements your source data needs to be an object similarly structured and not an array.
so this:
['name=ABC XYZ', 'hobbies=[M,N,O,P]', 'profession=S', 'age=27']
would need to become this:
const source= [{details_1: {"name":"ABC XYZ", "hobbies":"[M,N,O,P]", "profession":"S"}, details_2: {"age":"27"}}]
such that a call to Object.assign():
const new_person = Object.assign(person, source[0]);
fills this
const person = {
details_1: {
name: null,
hobbies: null,
profession: null
},
details_2: {
age: null
}
};
properly, though you may need to clone or instantiate and empty person first.
or, if person is an Object you could have a fill() method that knows what to do with the array data.

React extracting a nested json object

How can I extract the 'jobs' object from a nested json list like this:
result:
{
person:
[
{
name: ""
address: ""
jobs: [
{
company:""
},
{
company:""
}
]
}
]
}
Thank you
Write a generic method to extract object properties.
function onExtract(key, data) {
if (isObject(data)) {
for (let item in data) {
if (key === item) {
return data[item];
}
const res = onExtract(key, data[item]);
if (res !== null) return res;
}
}
if (isArray(data)) {
for (let item of data) {
const res = onExtract(key, item);
if (res !== null) return res;
}
}
return null;
}
function isObject(obj) {
return Object.prototype.toString.call(obj) === "[object Object]";
}
function isArray(arr) {
return Object.prototype.toString.call(arr) === "[object Array]";
}
// test
const data = {
person: [
{
name: "",
address: "",
jobs: [
{
company: ""
},
{
company: ""
}
]
}
]
};
console.log(onExtract("jobs", data));
let's say you have a return var that contains this json value
let mappedCompanies = return.person.map(person =>
person.jobs.map(job => job.company)
).flatMap(m => m)
mappedCompanies would contain an array with all the companies names for each one of the registers in "person", all as one array of strings
you can read more about Array.map() here: https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Array/map
A dynamic way to query the person[] and find jobs, is to use the javascript map() method.
Here is the code without comments.
const personsJobs = (personName, personAddress) => {
const jobs = result.person.map((el) => {
if (el.name === personName && el.address === personAddress) {
return el.jobs;
} else {
return null;
}
})
.filter((el) => el !== null);
return jobs;
};
console.log(personsJobs("wyatt", "1234 test ln"));
Here is the code with comments to explain how the personsJob function works.
// Blow is an ES6 arrow function with the parameters 'personName' and 'personAddress',
// which represents the person in which you are querying for jobs (using both a persons
// name and address so in the case of persons with the same name, you only find the jobs
// of the person you want).
const personsJobs = (personName, personAddress) => {
// Since 'person' is an array, we can use the 'map' method as stated before, which
// will create a new array (jobs) that will store the jobs a specific person has.
const jobs = result.person.map((el) => {
// el stands for the current position in the person array.
// if el's (the current person) name and address values are equal to that of the
// parameters personName and personAddress, then that persons jobs are added to the jobs // array, however, if el does not satisfy the two parameters, null is added to the jobs
// array.
// The array, upon completion, will look something like this: ["programmer", null, null]
if (el.name === personName && el.address === personAddress) {
return el.jobs;
} else {
return null;
}
})
// Finally, the filter method is called to remove all null values so that you will
// only have the persons job in the jobs array.
// After filtering, the array will look like this: ["programmer"]
.filter((el) => el !== null);
return jobs;
};
// Prints the array of wyatt's jobs
console.log(personsJobs("wyatt", "1234 test ln"));
So, following the conclusion of the function, you will have dynamically found the jobs of a specific person.
you can use flatMap function like:
const jobsData = result.person.flatMap(item => item.jobs);
Here is a flexible solution using object-scan
// const objectScan = require('object-scan');
const data = { person: [{ name: '', address: '', jobs: [{ company: '' }, { company: '' }] }] };
console.log(objectScan(['person[*].jobs'], { reverse: false, rtn: 'value' })(data));
// => [ [ { company: '' }, { company: '' } ] ]
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan#14.0.0"></script>
Disclaimer: I'm the author of object-scan

Promise not getting resolved inside reduce array method javascript

I have large array of objects and filtered the objects based on the userID. Here is the code below.
const filteredArr = LargeArr.Items.reduce(
async(acc, { attributes: { dob, name, picture} = { dob: null, name: null, picture: null }, userID }) => {
let pic = null;
if (picture) { pic = await getPic(picture); } // async here
acc[userID] = { name, userID, pic, dob };
return acc;
}, {});
Expected Output :
{
'1595232114269': {
name: 'Mark Status',
userID: '1595232114269',
picture: 'mark-status.jpg',
dob: '2020-08-10'
},
'48e69555d778f9b9a3a1d553b9c3b8f7dd6a3394ac82df1433b60a69c055d23d': {
name: 'Jack Thomas',
userID: '48e69555d778f9b9a3a1d553b9c3b8f7dd6a3394ac82df1433b60a69c055d23d',
picture: 'jack-thomas.jpg',
dob: '1990-12-20'
},
'48e69555d778f9b9a3a1d553b9c3b8f7dd6a3394ac82df1433b60a69c055d47p': {
name: 'Petro Huge',
userID: '48e69555d778f9b9a3a1d553b9c3b8f7dd6a3394ac82df1433b60a69c055d47p',
picture: 'petro huge.jpg',
dob: '1856-12-20'
},
'48e69555d778f9b9a3a1d553b9c3b8f7dd6a3394ac82df1433b60a69c055d55j': {
name: 'Mark Henry',
userID: '48e69555d778f9b9a3a1d553b9c3b8f7dd6a3394ac82df1433b60a69c055d55j',
picture: 'mark-henry.jpg',
dob: '2005-12-29'
}
}
I need to get picture from an api which is asynchronous, so used async await inside the reduce method. The problem here is it is always showing as Promise pending. If this was an array of object, then i can return Promise.all, but since this is object containing object how can i proceed with this inside reduce method? I need the exact same expected output.
Can somebody help me with this? Any help would be really appreciated.
To use reduce while iterating over items asynchronously, you'd have to have the accumulator which gets passed from callback to callback to be a Promise. While this is possible, it'll make things pretty difficult to read, and introduces some unnecessary syntax noise.
Use a plain for loop instead:
const filteredArr = {};
for (const item of LargeArr.Items) {
const { attributes: { dob, name, picture} = { dob: null, name: null, picture: null } } = item;
const pic = picture ? await getPic(picture) : null;
filteredArr[userID] = { name, uesrID, pic, dob };
}
If you really wanted to take the reduce route:
LargeArr.Items.reduce(
(acc, { attributes: { dob, name, picture} = { dob: null, name: null, picture: null }, userID }) => {
return acc.then(async (acc) => {
let pic = null;
if (picture) { pic = await getPic(picture); } // async here
acc[userID] = { name, userID, pic, dob };
return acc;
});
}, Promise.resolve({})
)
.then((filteredArr) => {
// do stuff with filteredArr
});
Unless the getPic calls need to be made in serial, you could consider using Promise.all instead, to iterate through the whole array at once, rather than waiting on the resolution of the prior Promise before going onto the next.
If your API can handle Promise.all:
const filteredArr = {};
await Promise.all(LargeArr.Items.map(async (item) => {
const { attributes: { dob, name, picture} = { dob: null, name: null, picture: null } } = item;
const pic = picture ? await getPic(picture) : null;
filteredArr[userID] = { name, uesrID, pic, dob };
}));

Assemble the data through JS Map

code1:
let commap = new Map();
data.forEach(function(item,index){
if(commap.has(item.comp)){
let arr = companyset.get(item.comp);
arr.push(item);
commap.set(item.comp,arr);
}else{
commap.set(item.comp,[item]);
}
});
code2:
let commap = new Map();
data.forEach(function(item,index){
commap .set(item.comp,commap.has(item.comp)?commap.get(item.comp).push(item):[item]);
});
The logic of the two pieces of code is the same, if there is more than one entry for company,code2 throw an error:'Uncaught TypeError: commap.get(...).push is not a function',
why did this error occur,is it the order of js execution?
Thanks a lot
The problem is that .push returns the new length of the array, not the array itself. So, when you set the value to companyset.get(item.company).push(item), you're setting the value to a number, not an array, which means when you try to push to it later, an error is thrown.
Remember that arrays, being non-primitive, can be changed simply with a reference to the array, without having to re-assign it. You only have to set the first time you come across a new company. Try something like this instead:
const data = [
{ company: 'foo' },
{ company: 'bar' },
{ company: 'foo' },
{ company: 'foo' },
];
const companyset = new Map();
data.forEach(function(item) {
const { company } = item;
const arr = companyset.get(company);
if (!arr) return companyset.set(company, [item]);
arr.push(item);
});
console.log(companyset.get('foo'));
But to combine an array into an object, it would be more appropriate to use reduce instead of forEach:
const data = [
{ company: 'foo' },
{ company: 'bar' },
{ company: 'foo' },
{ company: 'foo' },
];
const companyset = data.reduce((map, item) => {
const { company } = item;
const arr = map.get(company);
if (!arr) map.set(company, [item]);
else arr.push(item);
return map;
}, new Map());
console.log(companyset.get('foo'))

Categories

Resources