Why does this delete information from both jsons - javascript

I try to delete information from a JSON but when i put the og JSON to a new variable and then delete some of the information from both
example:
fs = require('fs');
var name = 'Assets/signup.json';
var m = JSON.parse(fs.readFileSync(name).toString());
const originalJSON = m;
let newJSONFile = originalJSON;
console.log(originalJSON)
newJSONFile.members.splice(0, newJSONFile.members.length)
console.log(originalJSON)
so this code should from what i know that it will asign a new JSON and then delete the members from newJSONFile and keep the members in the originalJSON but when i console.log(originalJSON) it output the members to be empty and i dont understand why

What looks like is your newJSONFile and originalJSON are both the same.
The objects in JS, they refer to same location. Unlike primitives we cant make a copy simply by using =. You can read more about it here
We can create deep copies using spread and other ways const newJSONFile = {...originalJSON} but this will still not deep copy the nested objects.
I am not aware of the structure your JSON is so can't suggest best way to create a deep copy.
You can use clone functions from libraries like lodash

UPDATED:
Create a deep clone of your original JSON, instead of just creating a reference. Then you can delete from the clone, and retain the original:
/* YOUR JSON FILE */
const newJSON = {
"howToUse": ",,photos {name} {instagram}",
"date": "April 8, 2021",
"available": "true",
"members": [
{
"name": "TinyruthlessPC",
"instagram": "Xclusiv3_Tester",
"signupDate": "April 10, 2021"
},
{
"name": "Tinyruthless",
"instagram": "Xclusiv3_Photography",
"signupDate": "April 10, 2021"
},
{
"name": "Kade",
"instagram": "Kade_Sucks",
"signupDate":"April 11, 2021"
}
]
}
/* LOG OG JSON FILE */
console.log(newJSON);
/* DEEP CLONE JSON FILE - MAKES A COPY */
let deepCloneJSON = JSON.parse(JSON.stringify(newJSON));
/* DELETE FROM THE COPY, NOT THE ORIGINAL */
delete deepCloneJSON.members[1];
console.log(deepCloneJSON);
/* CHECK THE ORIGNAL IS STILL INTACT */
console.log(newJSON);
https://jsfiddle.net/pixelmedia/7j18y5sp/12/
Old responses due to vague question:
Your question seems rather confusing, but if you are trying to delete from your JSON, then use the following.
Example: This will delete the second, and leave the first (0).
delete originalJSON[1];
Another example:
Initial is: 1, 2, 3
const originalJSON = [1, 2, 3];
delete originalJSON[1];
console.log(originalJSON);
Expected output: 1, 3
Now updated to demonstrate with the additional information provided by the OP:
const newJSON = {
"howToUse": ",,photos {name} {instagram}",
"date": "April 8, 2021",
"available": "true",
"members": [
{
"name": "TinyruthlessPC",
"instagram": "Xclusiv3_Tester",
"signupDate": "April 10, 2021"
},
{
"name": "Tinyruthless",
"instagram": "Xclusiv3_Photography",
"signupDate": "April 10, 2021"
},
{
"name": "Kade",
"instagram": "Kade_Sucks",
"signupDate":"April 11, 2021"
}
]
}
delete newJSON.members[1];
console.log(newJSON);
Expected output: removed 'Tinyruthless'
JSFiddle: https://jsfiddle.net/pixelmedia/7j18y5sp/1/

so my json will look like this:
{
"howToUse": ",,photos {name} {instagram}",
"date": "April 8, 2021",
"available": "true",
"members": [
{
"name": "TinyruthlessPC",
"instagram": "Xclusiv3_Tester",
"signupDate": "April 10, 2021"
},
{
"name": "Tinyruthless",
"instagram": "Xclusiv3_Photography",
"signupDate": "April 10, 2021"
},
{
"name": "Kade",
"instagram": "Kade_Sucks",
"signupDate":"April 11, 2021"
}
]
}
and i want to make it so that i can go through it and then delete one of the members and keep the rest in the same order
so i thought that i could just do
console.log(`deleteing person`)
fs = require('fs');
var name = 'Assets/signup.json';
var m = JSON.parse(fs.readFileSync(name).toString());
const originalJSON = m;
let newJSONFile = originalJSON;
console.log(originalJSON)
newJSONFile.members.splice(0, newJSONFile.members.length)
console.log(originalJSON)
for(m in originalJSON.members) {
console.log(`for loop runs`)
if(originalJSON.members[m]['name'] !== args[0]) {
let addMember = {
"name": originalJSON.members[m]['name'],
"instagram": originalJSON.members[m]['instagram'],
"signupDate": originalJSON.members[m]['signupDate']
}
newJSONFile.members.push(addMember)
console.log(newJSONFile)
}else {
}
}
and it just deletes it from both

Hi I used below script for this scenario.
const orgObj = { foo: "foo", bar: [1, 2, 3] }
var clonedObj = Object.assign({}, orgObj);
clonedObj.bar = Array.from(clonedObj.bar);
clonedObj.bar.push(4);
console.log(orgObj)
console.log(clonedObj)
It will make complete saperate copy of you object and OrgObj will remain unchanged.

Related

Lodash - Remove one property for every element in array without specify index

I'm building a component that allows me to compare two objects. It accepts a list of fields to compare and a list of fields that need to be ignored in string format
Here is an example of the object that will be compared:
{
// (..... More elements above .....)
taskData: {
"uniqueId": "OrdenTrabajo48",
"id": 48,
"position": 1,
"name": "Dirección Obra Civil",
"description": "Dirección Obra Civil Afecta: Sorda, Roberto",
"startDate": "2021-10-16T11:00:00.000Z",
"endDate": "2022-06-01T11:00:00.000Z",
"duration": 227,
"progress": 73,
"hours": 0,
"realHours": 15,
"predecessor": null,
"child": [],
"resourceInfo": [
{
"uniqueId": "Persona_1MJ0VE9G0",
"id": "OrdenTrabajo48Persona_1MJ0VE9G0",
"name": "Sorda, Roberto",
"group": "Subgerencia de Planes y Proyectos - SUB_PLAN_PROY_SIT",
"unit": 4.1667,
"startDate": "2021-10-16T03:00:00.000+00:00",
"endDate": "2022-06-01T02:59:59.000+00:00",
"hours": 0,
"realHours": 15,
"avatar": "http://localhost:8091/images/llama.jpg"
}
],
"comments": null,
"etiquetas": [],
"baseLineStartDate": null,
"baseLineEndDate": null
}
// (..... More elements below .....)
}
(But to clarify, it could be any object. The component is abstract and can be used anywhere)
The component doesn't know the structure of the object to compare, just the object and the paths in string format
I want to remove in every element of the array resourceInfo, the properties avatar, icon, label and color regardless the length of the array, but I don't know if there is a syntax to do that.
Also I want to remove the property realHours
This is what I tried:
const ignoredFields = [
'taskData.resourceInfo[?].avatar', //<--- It's not working
'taskData.resourceInfo[].icon', //<--- Neither this
'taskData.resourceInfo.label', //<--- Or this
'taskData.resourceInfo[0].color', //<--- This hardcode is working, but I don't know the length in that scope
'taskData.realHours' // <-- No problems here
];
const currentComparableObject = _.omit(obj, ignoredFields);
const oldComparableObject = _.omit(prev, ignoredFields);
var fieldsToOmit=[];
var resourceInfoFields=['avatar','icon','label','color'];
var globalFields=['realHours'];
taskData.resourceInfo.forEach((item,index)=>{
resourceInfoFields.forEach((field)=>{
fieldsToOmit.push(`resourceInfo[${index}].${field}`)
})
})
console.log( _.omit(taskData, fieldsToOmit.concat(globalFields)))
You do not need lodash to delete fields from an array. I mean you can if you really want to but, it is trivial to loop through the array and delete the fields you want.
#Yasser CHENIK isn't wrong just doesn't do a good job of explaining the solution.
Below I have included a thorough example so you can test for yourself.
NOTE this solution mutates the original array but, it is not difficult to use this concept to make an immutable version.
const taskData = {
"uniqueId": "OrdenTrabajo48",
"id": 48,
"position": 1,
"name": "Dirección Obra Civil",
"description": "Dirección Obra Civil Afecta: Sorda, Roberto",
"startDate": "2021-10-16T11:00:00.000Z",
"endDate": "2022-06-01T11:00:00.000Z",
"duration": 227,
"progress": 73,
"hours": 0,
"realHours": 15,
"predecessor": null,
"child": [],
"resourceInfo": [
{
"uniqueId": "Persona_1MJ0VE9G0",
"id": "OrdenTrabajo48Persona_1MJ0VE9G0",
"name": "Sorda, Roberto",
"group": "Subgerencia de Planes y Proyectos - SUB_PLAN_PROY_SIT",
"unit": 4.1667,
"startDate": "2021-10-16T03:00:00.000+00:00",
"endDate": "2022-06-01T02:59:59.000+00:00",
"hours": 0,
"realHours": 15,
"avatar": "http://localhost:8091/images/llama.jpg"
},
{
"uniqueId": "Persona_1MJ0VE9G0",
"id": "OrdenTrabajo48Persona_1MJ0VE9G0",
"name": "Sorda, Roberto",
"group": "Subgerencia de Planes y Proyectos - SUB_PLAN_PROY_SIT",
"unit": 4.1667,
"startDate": "2021-10-16T03:00:00.000+00:00",
"endDate": "2022-06-01T02:59:59.000+00:00",
"hours": 0,
"realHours": 15,
"avatar": "http://localhost:8091/images/llama.jpg"
},
{
"uniqueId": "Persona_1MJ0VE9G0",
"id": "OrdenTrabajo48Persona_1MJ0VE9G0",
"name": "Sorda, Roberto",
"group": "Subgerencia de Planes y Proyectos - SUB_PLAN_PROY_SIT",
"unit": 4.1667,
"startDate": "2021-10-16T03:00:00.000+00:00",
"endDate": "2022-06-01T02:59:59.000+00:00",
"hours": 0,
"realHours": 15,
"avatar": "http://localhost:8091/images/llama.jpg"
},
],
"comments": null,
"etiquetas": [],
"baseLineStartDate": null,
"baseLineEndDate": null
}
const fieldsToOmit = [
'avatar',
'icon',
'label',
'color',
'realHours'
]
console.log(taskData.resourceInfo);
taskData.resourceInfo.forEach(info => {
fieldsToOmit.forEach(field => {
delete info[field];
})
});
console.log(taskData.resourceInfo);
You can remove properties in a functional manner (immutable) by using destructuring:
const {realHours, ...result} = {
...taskData,
resourceInfo: taskData.resourceInfo.map(
({avatar, icon, label, color, ...keep}) => keep
)
};
console.log(result);
Thanks for the answers to all.
To solve partially the problem, I created a function that does the following:
It filters the references that contains [?] (i.e: taskData.resourceInfo[?].avatar)
Then obtain the first part of the string (That is, the path to reach the array) and the second part (property name)
Using _.get from lodash it retrieves the length of the array and creates a new fieldReference with the index, so loadash can read it.
private sanitizeArrays(obj: any, fieldReferences: string[]): string[] {
const fieldsDup = [...fieldReferences];
// Get Elements that contains [?] in the property name
const arrays = fieldsDup.filter(ignoredField => ignoredField.match(/\[\?]/g));
// Remove elements that contain [?] from ignoredFieldsDuplicated
fieldsDup.forEach((ignoredField, index) => {
if (ignoredField.includes('[?]')) {
fieldsDup.splice(index, 1);
}
});
// Get the properties names without [?]
const arrayPropertyName = arrays.map(ignoredField => ignoredField.split('[')[0]);
const afterArrayPropertyName = arrays.map(ignoredField => ignoredField.split(']')[1]);
// For each array that I have...
arrayPropertyName.forEach((array, index) => {
const length = _.get(obj, array).length;
for (let i = 0; i < length; i++) {
fieldsDup.push(array + '[' + i + ']' + afterArrayPropertyName[index]);
}
});
return fieldsDup;
}
Example input (if the object contains only one element in resourceInfo):
'taskData.resourceInfo[?].avatar',
'taskData.resourceInfo[?].icon',
'taskData.resourceInfo[?].label',
'taskData.resourceInfo[?].color',
'taskData.resourceInfo[?].fontColor',
'taskData.realHours'
Example output:
taskData.resourceInfo[?].icon
taskData.resourceInfo[?].color
taskData.realHours
taskData.resourceInfo[0].avatar
taskData.resourceInfo[0].icon
taskData.resourceInfo[0].label
taskData.resourceInfo[0].color
taskData.resourceInfo[0].fontColor
(javascript includes() isn't playing nice deleting the [?])
Also it doesn't work for nested arrays...

React Native how to create a VictoryPie from nested data

In my React Native application, I am accessing data from my store in the following form:
Array [
Checkout {
"date": 2020-12-27T13:24:08.734Z,
"id": "Sun Dec 27 2020 08:24:08 GMT-0500 (EST)",
"items": Array [
Object {
"productBrand": "Microsoft",
"productCategory": "Gaming",
"productId": "p1",
"productTitle": "Xbox",
"quantity": 2,
"x": 1.815,
},
Object {
"productBrand": "Apple",
"productCategory": "Computers",
"productId": "p2",
"productTitle": "MacBook Pro",
"quantity": 1,
"x": 1.905,
},
],
"total": 3.720,
},
Checkout {
"date": 2020-12-27T13:24:47.790Z,
"id": "Sun Dec 27 2020 08:24:47 GMT-0500 (EST)",
"items": Array [
Object {
"productBrand": "Apple",
"productCategory": "Computers",
"productId": "p2",
"productTitle": "MacBook Pro",
"quantity": 1,
"x": 1.905,
},
],
"total": 1.905,
},
]
I am trying to use VictoryPie to create a pie chart that shows productBrand weighted by the sum of x over all the objects. In this example, I would need a pie chart showing Microsoft and Apple, weighted by 1.815 and 2*1.905 = 3.81, respectively. Is there any way to do this without writing a separate function to calculate these sums? I would like the pie chart to update automatically every time new data is added to the store.
I tried this, where history is a variable containing the above array but no pie chart is produced.
<VictoryPie data={history} x={(data) => data.items.productBrand} y={(data) => data.items.x} />
See my working sample: https://codesandbox.io/s/react-victory-pie-chart-forked-kpe39?file=/src/index.js
Like this:
x="productBrand"
y={(data) => data.x * data.quantity}
For anyone trying to do something similar, I ended up extracting the data I needed by using a nested for loop within the useSelector hook:
const allBrands = useSelector(state => {
let allData = {};
for (const key1 in state.history.history) {
for (const key2 in state.history.history[key1].items) {
if (allData.hasOwnProperty(state.history.history[key1].items[key2].productBrand)) {
allData[state.history.history[key1].items[key2].productBrand] += state.history.history[key1].items[key2].x;
} else {
allData[state.history.history[key1].items[key2].productBrand] = state.history.history[key1].items[key2].x;
}
}
};
let dataArray = [];
for (const prop in allData) {
dataArray.push({ brand: prop, total: allData[prop] })
}
return dataArray
});
Passing allBrands to the VictoryPie data prop produced the correct pie chart.

Updating values of an object within array

I have an array of objects that looks like this:
[
{
"id": 123,
"timeStamp": "\"2019-07-08T20:36:41.580Z\"",
"data": [1, 2, 3]
},
{
"id": 234,
"timeStamp": "\"2019-07-08T20:37:12.472Z\"",
"data": ["Apples", "Oranges"]
}
]
I want to update the value of a particular property of an object within the array but also want to make sure that I return the result in a new array.
How do I do this without running through some type of a loop e.g. for loop?
Say, I want to update the data property of the second object and add Bananas to it.
If you want the result to be a new array, you'll first have to clone the array. This can be more complicated than you might imagine (depending on how deeply you wish to clone things). One way is to use JSON stringify...
Bear in mind that the JSON trick is effectively doing a loop behind the scenes. Inevitable if you want to copy the array, really.
To find the object by ID use Array.find()
let original = [
{
"id": 123,
"timeStamp": "\"2019-07-08T20:36:41.580Z\"",
"data": [1, 2, 3]
},
{
"id": 234,
"timeStamp": "\"2019-07-08T20:37:12.472Z\"",
"data": ["Apples", "Oranges"]
}
]
let copy = JSON.parse(JSON.stringify(original));
copy.find(obj => obj.id === 234).data.push("Bananas");
console.log(copy);
Something like this would do the trick:
let arr = [
{
"id": 123,
"timeStamp": "\"2019-07-08T20:36:41.580Z\"",
"data": [1, 2, 3]
},
{
"id": 234,
"timeStamp": "\"2019-07-08T20:37:12.472Z\"",
"data": ["Apples", "Oranges"]
}
]
arr[1]['data'] = [...arr[1]['data'], 'Bananas']
console.log(arr)
For your example: you can do something like this: say your array of object is saved in test variable
test[1].data.push("Bananas")

Is there a shorter/more efficient way to use the spread operator in javascript to update a key's value?

I recently got interested on using the spread operator syntax, so I tried some examples, I have this example of array:
var entities = [
{
"id": 1,
"age": 33,
"hobby": "games"
},
{
"id": 2,
"age": 28,
"hobby": "chess"
},
{
"id": 3,
"age": 21,
"hobby": "comics"
},
{
"age": 23,
"hobby": "games"
}
]
Then, to update all hobbies at "once" I do the following:
entities.forEach(function(entity, index) {
this[index] = {...entity, hobby: "Some String to update all hobbies"};
}, entities);
console.log(entities)
Which works but I was wondering if there's a more efficient or shorter way to achieve it while using the spread operator. Any suggestions?
EDIT:
forEach is not necessary for me, or even do it in that way, I was curious on whether the spread syntax could be used (or not) to update nested values
The spread operator doesn't really help when you're updating the list, like you do in your example. It's easier to just update the property of each object:
var entities = [ { "id": 1, "age": 33, "hobby": "games" }, { "id": 2, "age": 28, "hobby": "chess" }, { "id": 3, "age": 21, "hobby": "comics" }, { "age": 23, "hobby": "games" } ]
entities.forEach(entity => {
entity.hobby = "Some String to update all hobbies";
});
console.log(entities)
The spread operator is useful if you want to create copies of objects, like you might want to do in a .map:
var entities = [ { "id": 1, "age": 33, "hobby": "games" }, { "id": 2, "age": 28, "hobby": "chess" }, { "id": 3, "age": 21, "hobby": "comics" }, { "age": 23, "hobby": "games" } ]
const newEntities = entities.map(entity =>
({...entity, hobby: "Some String to update all hobbies"})
);
console.log(newEntities)
The spread operator will iterate over all keys in the object to copy them and their values into the new object. If you want more efficiency, don't use the spread operator. Just assign directly to each object as you iterate over the list:
entity.hobby = "Some String to update all hobbies"
Note that this modifies the object in the existing array. So you don't need to assign this[index]. Alternatively, you can use map() instead of foreach() to return a new array that is created from the existing array.
Not sure if spread operator is really needed for what you are doing?
You can also look into this link for some interesting usage of the spread, Array.from and rest operator.
More into just spread operator here.
If you are looking for a fancier/smaller way to write this, here's two, one that uses uses .map and spread to return a copy of entities, and another that uses .forEach and updates the same array entities:
const COMMON_HOBBY = 'Coding';
let entities = [{
"id": 1,
"age": 33,
"hobby": "games"
},
{
"id": 2,
"age": 28,
"hobby": "chess"
}];
// To assign to new array (copy)
let output = entities.map((entity) => ({...entity, hobby: COMMON_HOBBY }));
console.log(output);
// Mutate /edit same array entities
entities.forEach((entity) => entity.hobby = COMMON_HOBBY );
console.log(entities);

How can I add value's into existing JSON? [duplicate]

I got a JSON string with an array like this:
{
"Id": 123,
"Username": "Sr. X",
"Packages": [
{
"Name": "Cups",
"SupplierId": 1,
"ProviderGroupId": 575,
"SupplierName": "Foo Cups"
},
{
"Name": "Pins",
"SupplierId": 5,
"ProviderGroupId": 1082,
"SupplierName": "Foo Pins"
}
]
}
and I want to add a new field into Packages array like:
"Packages": [
{
"Name": "Cups",
"SupplierId": 1,
"ProviderGroupId": 575,
"SupplierName": "Foo Cups",
"New Field": "Value"
},...
Right now I can add a new field but in the main object, I'm using Json.NET library to do the job, but it seems that the documentation doesn't reach that level.
Have any one of you done it before?
JObject implemets IDictionary.
var jObj = JObject.Parse(json);
foreach(var item in jObj["Packages"])
{
item["New Field"] = "Value";
}
var newjson = jObj.ToString(Newtonsoft.Json.Formatting.Indented);
Try
JObject root = (JObject) JsonConvert.DeserializeObject(File.ReadAllText("products.json"));
JArray packages = (JArray) root["Packages"];
JObject newItem = new JObject();
newItem["Name"] = "Cups";
// ...
packages.Add(newItem);
Console.WriteLine(root); // Prints new json

Categories

Resources