How to change nested object attribute using JavaScript spread operator? - javascript

I have a JavaScript object like below
const obj = {
name: 'Jone',
location: {
presentAddress: {
livingAddress: {
City: {name: 'New York'},
Country: {name: 'USA'},
}
}
}
}
I'm trying to change city name New York to London
So, I have tried below code
console.log({
...obj,
location:{
...obj.location,
presentAddress:{
...obj.location.presentAddress,
livingAddress: {
...obj.location.presentAddress.livingAddress,
City:{
...obj.location.presentAddress.livingAddress.City,
name: "London"
}
}
}
}
})
It's working fine, My question is has there any shorter way to do this change?

Try setting the nested property directly.
obj.location.presentAddress.livingAddress.City.name = "London"

Related

Object with values as keys that store each individual object related to it using reduce: Javascript

just working through a problem and was wondering if anyone could shed some light on this issue I'm having. I'm supposed to take an array of objects (a set of parks) and I need to take a key from an object nested within it, use that as a new key and store an array of every object related by that same value we pulled for the key. Here's an example:
I'm working with data that looks a lot like this:
const myParks = [
{
name: "Garden of the Gods",
areaInSquareKm: 200,
location: {
state: "Colorado"
}
},
{
name: "Acadia",
areaInSquareKm: 198.6,
location: {
state: "Maine"
}
},
{
name: "Mountain Pass",
areaInSquareKm: 400.6,
location: {
state: "Colorado"
}
},
{
name: "Newleaf Forest",
areaInSquareKm: 150.4,
location: {
state: "Maine"
}
},
];
And I need to take the location.state value and use that as individual keys of a new object, then assign each key a value of the object with a related state. If the state is Maine, the key should contain the entire object with the related state:
{
"Maine": [
{
name: "Acadia",
areaInSquareKm: 198.6,
location: {
state: "Maine"
}
},
{
name: "Newleaf Forest",
areaInSquareKm: 150.4,
location: {
state: "Maine"
}
},
]
};
I was trying to do it like so:
function parkByState(parks) {
let stateParks = parks.reduce((result, park) => {
result[park.location.state] = parks.filter(park => { park.location.state })
}, {});
return stateParks
};
I can't for the life of me figure out how to do this properly. I can't change the structure, they MUST be assembled within an object, with the state names as keys, and have an array containing each individual park if the state matches the key. I just seriously don't know what I'm doing wrong. I keep getting an error:
Uncaught TypeError: Cannot set properties of undefined (setting 'Maine')
at <anonymous>:37:35
at Array.reduce (<anonymous>)
at parkByState (<anonymous>:36:26)
at <anonymous>:42:18
I'm relatively new to JavaScript and would love if anyone can shed some light on this. I needed to use the reduce() method to assemble the object. I figured using filter to filter the objects into each key would have made sense, but I can't seem to get the two methods to work together properly. You don't have to feed me the answer, but at the very least, please tell me what I'm doing wrong here. I've tried several different ways to do this and none seem to work. If I'm missing a key point of how to use these methods, please let me know what I can do to better understand what they are trying to do. I really appreciate all the help and I apologize if this is a dumb question. I'm just trying to understand how to reassemble an array of each park, stored in a key that is pulled from the state of each park. I'm sorry if the question isn't worded the absolute best, I really want to get better at this kind of stuff so I'm just trying to understand what I'm doing wrong here and how I can achieve the desired result.
Thank you in advance.
Without reduce we can do :
const myParks = [
{
name: "Garden of the Gods",
areaInSquareKm: 200,
location: {
state: "Colorado"
}
},
{
name: "Acadia",
areaInSquareKm: 198.6,
location: {
state: "Maine"
}
},
{
name: "Mountain Pass",
areaInSquareKm: 400.6,
location: {
state: "Colorado"
}
},
{
name: "Newleaf Forest",
areaInSquareKm: 150.4,
location: {
state: "Maine"
}
},
];
const stateNames = new Set(myParks.map(area => {
return area.location.state;
}));
const collectionsByStateName = {};
[...stateNames].forEach(stateName => {
collectionsByStateName[stateName] = [];
myParks.forEach(area => {
if(stateName === area.location.state) {
collectionsByStateName[stateName].push(area);
}
})
});
console.log(collectionsByStateName);
The callback that you pass to .reduce() should return a value. When you give an arrow funnction a body {} it must include return if you wish to return a value from it, otherwise, it will return undefined. Because you don't return anything from your reduce callback it currently returns undefined, so on the next iteration result will be undefined. This causes your error as you're trying to set a value of undefind which you can't do. Moreover, your .filter() needs to return a truthy value when you want to keep the value, and a falsy value when you want to discard it.
While you can do some modifications to your code to get the filter to work, I recommend not filtering at all. Instead, check what the current state is of the current park, and if that state is already in result, push to the existing array, otherwise, create a new key in result for that state with a new array holding the current state:
const myParks = [ { name: "Garden of the Gods", areaInSquareKm: 200, location: { state: "Colorado" } }, { name: "Acadia", areaInSquareKm: 198.6, location: { state: "Maine" } }, { name: "Mountain Pass", areaInSquareKm: 400.6, location: { state: "Colorado" } }, { name: "Newleaf Forest", areaInSquareKm: 150.4, location: { state: "Maine" } }, ];
function parkByState(parks) {
let stateParks = parks.reduce((result, park) => {
const key = park.location.state;
result[key] ??= []; // set `key` to an empty array if it doesn't exist, (similar to result[key] = result[key] || [];)
result[key].push(park);
return result;
}, {});
return stateParks;
};
console.log(parkByState(myParks));
As you said that you're new to JavaScript, I would do away with .reduce() here though. This particular example doesn't really need to use .reudce() and can be made more readable by using a for loop. I've also replace the nullish-coalescing operator with an if-statement which might ready more clearly if you're unfamiliar with ??
function parkByState(parks) {
const stateParks = {};
for(const park of parks) {
const key = park.location.state;
if(!stateParks[key])
stateParks[key] = [];
stateParks[key].push(park);
}
return stateParks;
}

How to merge nested json in snowflake?

object.assign is only perform the direct merge but its not working for nested json.
If anyone worked on this, could you please share the steps.
For example,I want to update the phone number and city of the user. City is under the location property. How should i update the value of city?
Example:
const user = {
name: "Liya",
phone: 12345,
location: {
city: "Camden",
country: "UK"
}
};
const updates = {
name: "David",
phone: 12345678,
location: {
city: "Smithfield"
}
};
Output should be like this:
console.log(Object.assign({}, user, updates));
{
name: 'Liya',
phone: 12345678,
location: {
country: 'UK',
city: 'Smithfield'
}
}
I'm assuming the name should be David since that's the name in the updates.
Based on #Han Moe Htet's comment, I used code from Vincent on that response. I used his because it does not require any external libraries, which Snowflake currently does not allow for Javascript UDFs.
There's an important consideration with this code. It uses recursion, and Snowflake UDFs have rather limited stack depth. If you have a highly nested object, it could run out of stack depth.
set USR = $${
name: "Liya",
phone: 12345,
location: {
city: "Camden",
country: "UK"
}
}$$;
set UPDATES = $${
name: "David",
phone: 12345678,
location: {
city: "Smithfield"
}
}$$;
create or replace function MERGE_OBJECTS("obj1" object, "obj2" object)
returns object
language javascript
strict immutable
as
$$
return merge(obj1, obj2);
function merge(current, updates) {
for (key of Object.keys(updates)) {
if (!current.hasOwnProperty(key) || typeof updates[key] !== 'object') current[key] = updates[key];
else merge(current[key], updates[key]);
}
return current;
}
$$;
with x as
(
select parse_json($USR) as USR, parse_json($UPDATES) as UPDATES
)
select merge_objects(USR, UPDATES) from X;

Update object property in javascript?

const [fields, setFields] = useState({
country: { country: "India" },
address: { street1: "street1", street2: "street2" },
});
This is my object. I want to update an inner property from this object
let id = 'street1'
let params = { ...fields, [id]: value }; //This will add a new prop
But i want to update the street1 inside the address object. How to do that?
Use this:
const updatedObject = {
...fields,
address: {
...fields.address,
[id]: value,
},
};
Try this
{...fields,address:{...fields.address,"street1":"abc"}}
let userAddress = {
country: { country: "India" },
address: { street1: "street1", street2: "street2" },
};
I believe the situation is to update the value of object that is nested , in this case street1.
Best way with ES6 would be to destructure and update the value.
userAddress = {
...userAddress,
address: { ...state.address, street1: newValue },
};

Clone an object introducing a new key-value pair if key with 'chart' is found - JS

I have a JS object
const data = {
names: {
chart1: 'arun'
},
city: 'New York',
zip: {
chart1: 11201
}
}
When I clone, I want to add a new key called chart2 (or incremental) whenever a key with a name 'chart' is found. Please advice.
This is what I did:
const newData = {
names: {
...data.names,
chart2: 'arun'
},
city: 'New York',
zip: {
...data.zip,
chart2: 11201
}
}
But, I want to handle it in a function.
Expected output:
{
city: "New York",
names: {
chart1: "arun",
chart2: "arun"
},
zip: {
chart1: 11201,
chart2: 11201
}
}
Please advice. The key should be incremental based on the largest value of the chart found. If I clone the above object, the new key should be chart3.
this code should work :
const newData = {
names: {
...data.names,
[`chart${Object.keys(data.names).length+1}`]: 'arun'
},
city: 'New York',
zip: {
...data.zip,
[`chart${Object.keys(data.zip).length+1}`]: 11201
}
}

javascript - map with conditionally altered nested field

Given an array such as:
people = [
{
name: 'Bob',
sex: 'male',
address:{
street: 'Elm Street',
zip: '12893'
}
},
{
name: 'Susan',
sex: 'female',
address:{
street: 'Hickory Street',
zip: '00000'
}
}
]
I am trying to write a function which will alter specific instances of '00000' in the nested field 'zip' to the string '12893' and return a new array identical to the initial array except with the corrected values. My attempt at a function so far is:
function zipFix (initialArray) {
return initialArray.map(function(person) {
if(person.address.zip === '00000')
person.address.zip = "12893"
return person
});
}
I know this function is altering the values in 'initialArray', which isn't supposed to happen. How can I go about writing my function so that I can effectively use the map function to create a new, corrected array? Thanks.
While map-ing over the values, you will need to create a copy of each object. The easiest way to do so is with the object spread syntax ({...obj}).
This will "spread" all the values (name, adress, etc) into a new object. So any changes won't mutate it. However, it's "shallow" meaning it will be a new object but its values are the same. So since address is also an object we need to copy that as well, hence the reason for the nested spread of the address value as well.
people = [{
name: 'Bob',
sex: 'male',
address: {
street: 'Elm Street',
zip: '12893'
}
},
{
name: 'Susan',
sex: 'female',
address: {
street: 'Hickory Street',
zip: '00000'
}
}
]
function zipFix(initialArray) {
return initialArray.map(function(person) {
// Create a new "copy" of the person. Using object spread
// will create a "shallow" copy, so since address is also an
// object it will have to be spread (same for other objects that might
// be mutated).
const newValue = { ...person, address: { ...person.address }}
if (newValue.address.zip === '00000') {
newValue.address.zip = "12893";
}
return newValue
});
}
console.log(zipFix(people))
console.log(people) // unchanged
You need to return values from callback function too, also make a copy of element before assigning to avoid mutability
const people = [{name: 'Bob',sex: 'male',address:{street: 'Elm Street',zip: '12893'}},{name: 'Susan',sex: 'female',address:{street: 'Hickory Street',zip: '00000'}}]
function zipFix (initialArray) {
return initialArray.map(function(person) {
let newObj = JSON.parse(JSON.stringify(person))
if(newObj.address.zip === '00000')
newObj.address.zip ="12893"
return newObj
});
}
console.log(zipFix(people))
people = [{
name: 'Bob',
sex: 'male',
address: {
street: 'Elm Street',
zip: '12893'
}
},
{
name: 'Susan',
sex: 'female',
address: {
street: 'Hickory Street',
zip: '00000'
}
}
]
function zipFix (initialArray) {
return (initialArray.map(({address, ...p}) => (
address.zip !== '00000' ? { ...p, address } : {
...p,
address: {
...address,
zip: '12893'
}
}
)));
}
console.log(zipFix(people));
You can do:
const people = [{name: 'Bob',sex: 'male',address: {street: 'Elm Street',zip: '12893'}},{name: 'Susan',sex: 'female',address: {street: 'Hickory Street',zip: '00000'}}]
const zipFix = people.map(({address, ...p}) => ({
...p,
address: {
...address,
zip: address.zip === '00000' ? '12893' : address.zip
}
}))
console.log(zipFix)

Categories

Resources