destructuring nested level of array of object - javascript

I have an object where one property contains array of objects, I need to destructure it, but when destructuring I don't know how to handle if that property is of empty array
const dataTest1 = {
id: 1,
details: [{f_name_1: "John"}]
}
const {details : [{f_name_1}] = [{}]} = dataTest1 || {}
console.log(f_name_1 ?? 'NA')
const dataTest2 = {
id: 2
}
const {details : [{f_name_2}] = [{}]} = dataTest2 || {}
console.log(f_name_2 ?? 'NA')
const dataTest3 = {
id: 3,
details: []
}
const {details : [{f_name_3}] = [{}]} = dataTest3 || {}
console.log(f_name_3 ?? 'NA')
If you see the first and second case gives me value or fallback value, but when I pass details as an empty array its going error (dataTest3), because I am destructuring first position of array [{}], how can I give a default value as empty object

You need an object ad default value for the inner object, because you add only an array if the array is missing, but if exist, you have no object.
const dataTest3 = {
id: 3,
details: []
}
const { details: [{ f_name_3 } = {}] = [] } = dataTest3 || {};
console.log(f_name_3 ?? 'NA');

Related

How to update an object value in array of objects when the keys are same

I have an Array of objects and one object
const filterArray = [{bestTimeToVisit: 'Before 10am'}, {bestDayToVisit: Monday}]
This values are setting in a reducer and the payload will be like
{bestTimeToVisit: 'After 10am'}
or
{bestDayToVisit: Tuesday}.
So what I need is when I get a payload {bestTimeToVisit: 'After 10am'} and if bestTimeToVisit not in filterList array, then add this value to the filterList array.
And if bestTimeToVisit already in the array with different value, then replace the value of that object with same key
if(filterArray.hasOwnProperty("bestTimeToVisit")) {
filterArray["bestTimeToVisit"] = payload["bestTimeToVisit"];
} else {
filterArray.push({"bestTimeToVisit": payload["bestTimeToVisit"]});
}
I convert the object array into a regular object and then back into an object array. makes things less complicated. I'm making the assumption each object coming back only has one key/value and that order doesnt matter.
const objectArraytoObject = (arr) =>
arr.reduce((acc, item) => {
const key = [Object.keys(item)[0]];
return { ...acc, [key]: item[key] };
}, {});
const newValues = [{ someKey: 'something' }, { bestDayToVisit: 'Tuesday' }];
const filterArray = [
{ bestTimeToVisit: 'Before 10am' },
{ bestDayToVisit: 'Monday' },
];
const newValuesObj = objectArraytoObject(newValues);
const filterObj = objectArraytoObject(filterArray);
const combined = { ...filterObj, ...newValuesObj };
const combinedToArray = Object.keys(combined).map((key) => ({
[key]: combined[key],
}));
console.log(combinedToArray);
Need to iterate over the array and find objects that satisfy for modification or addition if none are found.
function checkReduced(filterrray,valueToCheck="After 10am"){
let isNotFound =true;
for(let timeItem of filterrray) {
if(timeItem.bestTimeToVisit && timeItem.bestTimeToVisit !== valueToCheck) {
timeItem.bestTimeToVisit=valueToCheck;
isNotFound=false;
break;
}
}
if(isNotFound){filterrray.push({bestTimeToVisit:valueToCheck})}
}
const filterArray = [{bestDayToVisit: "Monday"}];
checkReduced(filterArray,"After 9am");//calling the function
const updateOrAdd = (arr, newItem) => {
// get the new item key
const newItemKey = Object.keys(newItem)[0];
// get the object have the same key
const find = arr.find(item => Object.keys(item).includes(newItemKey));
if(find) { // the find object is a reference type
find[newItemKey] = newItem[newItemKey]; // update the value
} else {
arr.push(newItem); // push new item if there is no object have the same key
}
return arr;
}
// tests
updateOrAdd([{ a: 1 }], { b: 2 }) // => [{ a: 1 }, { b: 2 }]
updateOrAdd([{ a: 1 }], { a: 2 }) // => [{ a: 2 }]

Constructing object array using dynamic keys in react/Javscript

I tried to contrcut the object based on response coming from API.
my key is assigned this.RootKeyValue and my response is assigned to this.keyResponse
this.RootKeyValue is the key of parent of first object .
In second object based on the DynamicKey value need to create the key and values .
this.RootKeyValue = "AccountDetails";
this.keyResponse =
[
{ICICI: 2,DynamicKey: "ICICI"},
{SBI: 1.25,DynamicKey: "SBI"}
{HDFC: 1.75,DynamicKey: "HDFC"}
]
how to construct the object like below using above key and response.
Expected result :
{
AccountDetails :
{ ICICI :2 , SBI: 1.25,HDFC: 1.75 }
}
I am new to react please suggest how to construct object using the dynamic key values
You build a dynamic object using square bracket notation
const obj = { ["SomeDynamicKey"]: someValue }
So in your case you can use reduce to build the object from your array:
this.RootKeyValue = "AccountDetails";
this.keyResponse =
[
{ICICI: 2,DynamicKey: "ICICI"},
{SBI: 1.25,DynamicKey: "SBI"},
{HDFC: 1.75,DynamicKey: "HDFC"}
]
const result = {
[this.RootKeyValue] : this.keyResponse.reduce( (acc,item) => ({
...acc,
[item.DynamicKey]: item[item.DynamicKey]})
,{})
}
console.log(result)
As the give array already has the dynamic keys and associate value in same object , you can create your desired object very easily like this.
let given = [
{ICICI: 2,DynamicKey: "ICICI"},
{SBI: 1.25,DynamicKey: "SBI"},
{HDFC: 1.75,DynamicKey: "HDFC"}
] , AccountDetails = {};
given.forEach(item => {
AccountDetails[item.DynamicKey] = item[item.DynamicKey] ? item[item.DynamicKey] : '';
})
console.log(AccountDetails);
You can use square brackets to handle this very easily, e.g.
const key = 'DYNAMIC_KEY';
const obj = { [key]: 'value' };
const RootKeyValue = "AccountDetails";
const keyResponse = [
{ ICICI: 2,DynamicKey: "ICICI" },
{ SBI: 1.25,DynamicKey: "SBI" },
{ HDFC: 1.75,DynamicKey: "HDFC" }
];
const newData = { [RootKeyValue]: {} };
keyResponse.forEach(item => {
newData[RootKeyValue][item.DynamicKey] = item[item.DynamicKey];
})
console.log(newData)

JS get value of nested key with changing parent name

I need to get the value of roles in the following example.
const obj ={
id: 1,
"website.com": {
roles: ["SuperUser"]
}
}
const r = obj.hasOwnProperty("roles")
console.log(r)
Its parent objects name ("website.com") can change everytime as Im requesting it from the db. What is the best way to get this variable?
The obj would also be relatively large I just didnt include it in the example.
You could iterate over the object and exclude id. Example:
for (var x in obj) {
if (x !== 'id') {
console.log(obj[x].roles)
}
}
EDIT (to address your question edit):
If the root object has many keys, it would probably make sense to instead either move the domain from a key to a value (for example, domain: 'website.com' and move the roles up (flattening the object); or you could check for a key that looks like a domain using a regex. Example: if (/^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9](?:\.[a-zA-Z]{2,})+$/.test(x) rather than if (x !== 'id'). The regex way would probably be brittle.
EDIT 2:
You could use the hasOwnProperty check like this:
let roles
for (let x in obj) {
if (obj[x].hasOwnProperty(roles)) {
roles = obj[x])
}
}
You can get the roles by destructuring the roles property from the value of obj['website.com'].
If you want to do this dynamically, you will need to figure out key has a corresponding object with the property roles. Once you find all valid candidates, you can access the first (or whichever one you want) and then grab its value.
const hasRoles = obj => Object.entries(obj)
.filter(([key, value]) =>
value.hasOwnProperty('roles'));
const obj = {
id: 1,
"website.com": {
roles: ["SuperUser"]
}
}
const [ first ] = hasRoles(obj);
const [ website, { roles } ] = first;
console.log(`website = ${website} | roles = ${roles}`);
Alternatively, for a greedy match:
const hasRolesGreedy = obj => Object.entries(obj)
.find(([key, value]) =>
value.hasOwnProperty('roles'));
const obj = {
id: 1,
"website.com": {
roles: ["SuperUser"]
}
}
const found = hasRolesGreedy(obj);
const [ website, { roles } ] = found;
console.log(`website = ${website} | roles = ${roles}`);
only access to the nested key like this:
let roles = obj["website.com"].roles;
console.log(roles);
That way, you will get an array, then you can iterate or get a value by the index.
Since you don't know what the name is, you need to iterate over all properties and find the first with the roles property:
const testObj ={
id: 1,
"website.com": {
roles: ["SuperUser"]
}
}
const testObj2 = {
id: 2,
"anotherwebsite.com":{
roles: ["AnotherSuperUser"]
}
}
function getRoles(obj){
for(let x in obj){
if(Object.prototype.hasOwnProperty.call(obj, x))
{
if(obj[x].roles){
return obj[x].roles;
}
}
}
return undefined;
}
console.log(getRoles(testObj));
console.log(getRoles(testObj2));

How to assign a nested property of an object given an array of keys [duplicate]

This question already has answers here:
How to set value to a property in a Javascript object, which is identified by an array of keys
(2 answers)
Closed 3 years ago.
I have an object that resembles this:
const obj = {
prop1: {
prop2: {
value: 'something',
...otherProps
}
},
...otherProps
}
And an array that looks like this:
const history = ['prop1', 'prop2', 'value']
How do I assign the property value of prop2 a new value in a way that would also work for any other depth.
Just loop through the property list and get each property of the object.
const obj = {
prop1: {
prop2: {
value: 'something'
}
}
};
const history = ['prop1', 'prop2', 'value'];
console.log(setPropertyValue(obj, history, "test"));
console.log(getPropertyValue(obj, history));
function getPropertyValueContainer(values, propertyList) {
var copy = propertyList.slice(), propertyName = copy.pop();
for (var property of copy) values = values[property];
return { propertyName: propertyName, values: values };
}
function getPropertyValue(values, propertyList) {
var container = getPropertyValueContainer(values, propertyList);
return container.values[container.propertyName];
}
function setPropertyValue(values, propertyList, value) {
var container = getPropertyValueContainer(values, propertyList);
return container.values[container.propertyName] = value;
}
You can use references.
So here i am taking reference of object in a variable untill i key equal to value and than adding value using that ref.
const obj = { prop1: { prop2: { value: 'something'}}}
const history = ['prop1', 'prop2', 'value']
let ref = obj;
history.forEach((e,index)=>{
if(e !== 'value' ) ref = ref[e]
})
ref.value = 'xyz'
console.log(obj)

How can you destructure an array of objects in Javascript into two predefined variables in ES6?

I have an array containing one object of this form :
Array = [ { type: type, message: message } ]
I keep getting ESLint errors asking me to use object destructuring and array destructuring.
Currently my code looks like this :
let type=null;
let message=null;
if (data.length > 0) {
({ type, message } = data[0]);
}
So far this works and my variables are assigned correctly, however I am still getting the "Use array destructuring" message from ESLint.
Any help with this would be appreciated. Thank you
You can destructure the array:
let type=null;
let message=null;
if (data.length > 0) {
[{ type, message }] = data;
}
The code above is a shorter version of:
[ firstElement ] = data; // array destructruring
({ type, message } = firstElement); // object destructuring
Faly's way is good. You can also use default values when destructuring:
function test(label, data) {
// 1 -----------------------------vvvvv
let [{type = null, message = null} = {}] = data;
// 2 -----^^^^^^^---------^^^^^^^
console.log(label, type, message);
}
test("test1: ", []);
test("test2: ", [{type: "t"}]);
test("test3: ", [{type: "t", message: "m"}]);
That works because if data.length is 0, data[0] is undefined, and so triggers use of the default value {} (1) for the array part of that; within the object part of that, we use null (2) to handle any missing values on the object as well.
EsLint wants you to write
let type = null;
let message = null;
if (data.length > 0) {
[{ type, message }] = data;
}
which destructures the first item of an iterable data into the {type, message} target. (More items are ignored).
I would however recommend to use default values for the empty case:
const [{type, message} = {type:null, message:null}] = data;
or also
const [{type = null, message = null} = {}] = data;

Categories