Update values on multi level nested Object with javascript - javascript

I have an Object on sessionStorage for which I need to update values on user input. I am able to update at the root of the Object but not the values that are nested on a deeper level.
request('http://localhost:7474/graphql/', query).then(data => {...}
sessionStorage.setItem('queryData', JSON.stringify(data));
function update(value){
let prevData = JSON.parse(sessionStorage.getItem('queryData'));
Object.keys(value).forEach(function(val, key){
prevData[val] = value[val];
});
sessionStorage.setItem('queryData', JSON.stringify(prevData));
}
update({ maritalStatus: "single" });
So maritalStatus ends up been added and not replaced and I must replace the value:
Object: [,...]
0: {id: "x", maritalStatus: "married"} //want to replace this value here
maritalStatus: "single" // this is where the value is been written

Your data in storage is an Array. So the way you are updating it like prevData[val] = value[val]; is adding another property to the array with index of maritalStatus and value of "single". The object at index 0 is untouched.
My suggested fix is to also include the id in your update call. Then loop through the array in storage and look for the object with the matching id.
Once the id matches update that object, or log if no id matches are found.
let dataInStorage = [{
id: "x",
maritalStatus: "married"
}];
function update(updateObj) {
let prevData = dataInStorage;
let id = updateObj.id;
dataInStorage.forEach(function(data) {
if (data.id === id) {
Object.keys(updateObj).forEach(function(key, index) {
data[key] = updateObj[key];
});
} else {
console.log(`did not find object with id: ${id}`);
}
});
console.log(prevData)
//sessionStorage.setItem('queryData', JSON.stringify(prevData));
}
update({
id: "x",
maritalStatus: "single"
});

Related

How to check if a value exists in array with .includes?

I know we can use .includes but I've been struggling to get it to work with my array. What I want is for my function to check if the value already exists and if it does to remove it from the array.
The value is a string. That value comes from an object that has .name as a property within the object.
0: {id: 190217270, node_id: 'MDEwOlJlcG9zaXRvcnkxOTAyMTcyNzA=', name: '3-Bit-CNC-Starter-Pack'}
1: {id: 187179414, node_id: 'MDEwOlJlcG9zaXRvcnkxODcxNzk0MTQ=', name: 'inb-go'}
I mapped through the data and assigned each button with a value of {d.name}
I am using a button to get the value with this function below
and adding the values to 'favs'.
const favs = [];
function checkId(e) {
if (e.target.value !== "")
favs.push(e.target.value);
localStorage.setItem("name", JSON.stringify(favs));
console.log(favs);
document.getElementById("favsarray").innerHTML = favs;
}
console.log
favs
[
"3-Bit-CNC-Starter-Pack",
"3-Bit-CNC-Starter-Pack"
]
How can I check to see if the value already exists within the array using .includes?
Just check before push:
function checkId(e) {
if (e.target.value !== ""
&& !favs.includes(e.target.value))
{
favs.push(e.target.value);
// other code here
}
}
["Sam", "Great", "Sample", "High"].includes("Sam"); // true
if not false

Why doesn't reassigning the parameter element in forEach work

For the following code block:
const items = [
{ id: 1, name: 'one' },
{ id: 2, name: 'two' },
];
const changes = {
name: 'hello'
}
items.forEach((item, i) => {
item = {
...item,
...changes
}
})
console.log(items) // items NOT reassigned with changes
items.forEach((item, i) => {
items[i] = {
...item,
...changes
}
});
console.log(items) // items reassigned with changes
Why does reassigning the values right on the element iteration not change the objects in the array?
item = {
...item,
...changes
}
but changing it by accessing it with the index does change the objects in the array?
items2[i] = {
...item,
...changes
}
And what is the best way to update objects in an array? Is items2[i] ideal?
Say no to param reassign!
This is a sort of a fundamental understanding of higher level languages like JavaScript.
Function parameters are temporary containers of a given value.
Hence any "reassigning" will not change the original value.
For example look at the example below.
let importantObject = {
hello: "world"
}
// We are just reassigning the function parameter
function tryUpdateObjectByParamReassign(parameter) {
parameter = {
...parameter,
updated: "object"
}
}
tryUpdateObjectByParamReassign(importantObject)
console.log("When tryUpdateObjectByParamReassign the object is not updated");
console.log(importantObject);
As you can see when you re-assign a parameter the original value will not be touched. There is even a nice Lint rule since this is a heavily bug prone area.
Mutation will work here, but ....
However if you "mutate" the variable this will work.
let importantObject = {
hello: "world"
}
// When we mutate the returned object since we are mutating the object the updates will be shown
function tryUpdateObjectByObjectMutation(parameter) {
parameter["updated"] = "object"
}
tryUpdateObjectByObjectMutation(importantObject)
console.log("When tryUpdateObjectByObjectMutation the object is updated");
console.log(importantObject);
So coming back to your code snippet. In a foreach loop what happens is a "function call" per each array item where the array item is passed in as a parameter. So similar to above what will work here is as mutation.
const items = [
{ id: 1, name: 'one' },
{ id: 2, name: 'two' },
];
const changes = {
name: 'hello'
}
items.forEach((item, i) => {
// Object assign just copies an object into another object
Object.assign(item, changes);
})
console.log(items)
But, it's better to avoid mutation!
It's better not mutate since this can lead to even more bugs. A better approach would be to use map and get a brand new collection of objects.
const items = [{
id: 1,
name: 'one'
},
{
id: 2,
name: 'two'
},
];
const changes = {
name: 'hello'
}
const updatedItems = items.map((item, i) => {
return {
...item,
...changes
}
})
console.log({
items
})
console.log({
updatedItems
})
As the MDN page for forEach says:
forEach() executes the callbackFn function once for each array
element; unlike map() or reduce() it always returns the value
undefined and is not chainable. The typical use case is to execute
side effects at the end of a chain.
Have a look here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
This means that although you did create new object for item, it was not returned as a value for that index of array. Unlike your second example, the first one is not changing original array, but just creates new objects and returns undefined. This is why your array is not modified.
I'd go with a classic Object.assign for this:
const items = [
{ id: 1, name: 'one' },
{ id: 2, name: 'two' },
];
const changes = {
name: 'hello'
}
items.forEach( (item) => Object.assign(item,changes) )
console.log(items)
Properties in the target object are overwritten by properties in the sources if they have the same key. Later sources' properties overwrite earlier ones.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
The other approach you can take is to use map and create a new array based on the original data and the changes:
const items = [
{ id: 1, name: 'one' },
{ id: 2, name: 'two' },
];
const changes = {
name: 'hello'
}
const newItems = items.map((item) => {
...item,
...changes
})
console.log(newItems);
But if you need to modify the original array, it's either accessing the elements by index, or Object.assign. Attempting to assign the value directly using the = operator doesn't work because the item argument is passed to the callback by value not by reference - you're not updating the object the array is pointing at.

Matching value of data object in VueJs

How can I retrieve the data from a data object in Vue?
I have data in this format:
datasets: [{
text:"Cars",
value: "[1,2,3]"
},
{
text:"Trains",
value: "[1,4,10]
}
]
Now I from route props I get the following info:
this.selectedText= this.$route.name;
Where this.$route.name is "Cars" for example.
Now I want to take this use this.selectedValue to get corresponding Value from this array:
so if this.selectedText="Cars" then this.selectedValue=[1,2,3] or based on this I want to retrieve the value of given text.
Create a method and use this code to find out the matching one.
function setSelectedValue() {
let matchingDatSet = this.datasets.find(ele => ele.text == this.selectedText);
if(matchingDataSet !== undefined) {
this.selectedValue = matchingDataSet.value;
}
}

update nested Object data without changing Object Id

I am currently using array filters to update the nested object.
My structure is -
Category Collection -
{
name:Disease,
_id:ObjectId,
subCategory:[{
name:Hair Problems,
_id:ObjectId,
subSubCategory:[{
name: Hair Fall,
_id:ObjectId
},{
name: Dandruff,
_id:ObjectId
}]
}]
}
I want to update the subsubcategory with id 1.1.1 which I am doing by using array filters.
let query = { 'subCategories.subSubCategories._id': subSubId };
let update = { $set: { 'subCategories.$.subSubCategories.$[j]': data } };
let option = { arrayFilters: [{ 'j._id': subSubId }], new: true };
await Categories.findOneAndUpdate(query, update, option
This code is working fine but array filters change the object id of subsubCategory. Is there any other alternative to do so without changing the ObjectId.
Thanks in advance
You can loop over the keys which you are getting as payload and put inside the $set operator.
const data = {
firstKey: "key",
secondKey: "key2",
thirdKey: "key3"
}
const object = {}
for (var key in data) {
object[`subCategories.$.subSubCategories.$[j].${key}`] = data[key]
}
let query = { 'subCategories.subSubCategories._id': subSubId };
let update = { '$set': object };
let option = { 'arrayFilters': [{ 'j._id': subSubId }], 'new': true };
await Categories.findOneAndUpdate(query, update, option)
Problem is in $set line there you have not mentioned specific fields to be update instead subCategory.$.subSubCategory.$[j] will replace complete object element that matches the _id filter. Hence your _id field is also getting updated. You have to explicitly mention the field name after array element identifier. See example below:
Suppose you want to update name field in subSubCategories from Dandruff to new Dandruff. Then do this way:
let update = { $set: { 'subCategories.$.subSubCategories.$[j].name': "new Dandruff" } };
This will only update name field in subSubCategories array

psuhing an object inside another object

I want to create an object of objects which should be something like this.
let data={
{ _id:10010,
value:"tom"
},
{
_id:2002,
value:22882
}
}
One solution that i could think of was this .
let data = {};
data.content = ({
_id: 1001,
value: "tom"
});
data.content = ({
id: 10001,
status: "harry"
});
console.log(data);
However if we do this we can only have one content inside our main object .Can we accomplish the desired data format while creating an object of objects ?
You can use array.
let data=[
{ _id:10010,
value:"tom"
},
{ _id:2002,
value:22882
}
]
data.push({
_id:1001,
value:"tom"
});
data.push({
_id:1001,
value:"tom"
});
Push method will add object to the array. If you need something else you can create more complex function/class that handles the requirements, but this maybe would be enough.
I assume you need to do with array
let data=[];
data.push({
_id:1001,
value:"tom"
});
data.push({
id:10001,
status:"harry"
});
console.log(data);
You cannot create an "object of objects". Objects store data in key:value pairs. You might consider creating an array of objects, after which you can reference the array items using indexes:
let data = [];
data.push({
_id: 10010,
value: "tom"
});
data.push({
_id: 2002,
value: 22882
});
console.log(data);
You can make use of arrays in order to achieve the result.
let data = [];
data[0]= {
_id:10010,
value:"tom"
}
data[1]= {
_id:2002,
value:22882
}
and so on...
I believe what you really mean is
let data={
10010: { _id:10010,
value:"tom"
},
2002: {
_id:2002,
value:22882
}
}
Property of objects has to be key value pair, meaning in order to have a object nested in an object, as a value, u need to pair it with a key. Hence using the id of object as the key to store it.
data['10010'] = { _id: 10010, value: 'tom' };
data['2002'] = { _id: 2002, value: 22882 };

Categories