How to change values of every id in this nested object array? - javascript

I have data structure similar like this
{"id": 1, "a": [{"id": 2, "b": [{"id": 3, "c": [{"id": 4}]}]}]}
I would like to change every id to null.
I know I could do loops and manually assign null to id. Is there any easy way to do this in JavaScript?

Without changing the object to a JSON string, you could use recursion:
function clearIds(obj) {
if ("id" in Object(obj)) obj.id = null;
Object.values(Object(obj)).forEach(clearIds);
}
// Demo
let obj = {"id": 1, "a": [{"id": 2, "b": [{"id": 3, "c": [{"id": 4}]}]}]};
clearIds(obj);
console.log(obj);
This mutates the given object in place.
For fun: the same function as a one-liner:
const clearIds = o => "id" in Object(o) && (o.id = null) || Object.values(Object(o)).forEach(clearIds);
// Demo
let obj = {"id": 1, "a": [{"id": 2, "b": [{"id": 3, "c": [{"id": 4}]}]}]};
clearIds(obj);
console.log(obj);

Bravo's comment was illuminating so I hope they don't mind if I expand on it here.
Turn the object into a string.
Parse it back into an object again.
What I didn't know is that JSON.parse has a "reviver" function that allows you to transform the string value as it's being parsed.
const data = {"id": 1, "a": [{"id": 2, "b": [{"id": 3, "c": [{"id": 4}]}]}]};
// Turn the data into a string
const str = JSON.stringify(data);
// Parse the string back to an object
// but using the reviver function to turn the value of any id
// keys to null
const newObj = JSON.parse(str, (key, value) => key === 'id' ? null : value);
console.log(newObj);

Related

Copying objects in js (need guidance on pass by reference from docs)

I looked in the js docs and while studying the doc it mentioned in object.assign()
If the source value is a reference to an object, it only copies the reference value.
In my below snippet, one alters the original object and the other doesn't
var objA = {
a: 1,
b: {
c: 2,
d: {
e: 3,
},
},
}
var objC = { t: 1 };
//why this works i.e adds a to objEmpty
// var objEmpty = Object.assign({}, { objC }); //this would add a prop to the objEmpty object
//this doesnt work i.e doesnt add a to objEmpty
var objEmpty = Object.assign({}, objC); //this will not
objC.a = 3;
console.log(objC);
console.log(objEmpty);
I am getting my head around how really things work by trying different scenarios and I believe that it is something related to reference but how?
Another example from the docs
const obj2 = Object.assign({}, obj1);
console.log(JSON.stringify(obj2)); // { "a": 0, "b": { "c": 0}}
obj1.a = 1;
console.log(JSON.stringify(obj1)); // { "a": 1, "b": { "c": 0}}
console.log(JSON.stringify(obj2)); // { "a": 0, "b": { "c": 0}}
obj2.a = 2;
console.log(JSON.stringify(obj1)); // { "a": 1, "b": { "c": 0}}
console.log(JSON.stringify(obj2)); // { "a": 2, "b": { "c": 0}}
obj2.b.c = 3;
console.log(JSON.stringify(obj1)); // { "a": 1, "b": { "c": 3}}
console.log(JSON.stringify(obj2)); // { "a": 2, "b": { "c": 3}}```
why does js behave this way? why the 3 got changed but the other didn't?
Thanks in advance :)
why does js behave this way? why the 3 got changed but the other
didn't?
Because Object.assign() actually does Shallow Copy, you need to do Deep Copy
To do deep copy of an object.
There are bunch of ways, The most common and popular way is to use JSON.stringify() with JSON.parse().
const oldObj = {a: {b: 1}, c: 2};
const newObj = JSON.parse(JSON.stringify(oldObj));
oldObj.a.b = 3; // will not affect the newObj
console.log('oldObj', oldObj);
console.log('newObj', newObj);
Note: There's a new JS standard called structured cloning. It works on all browsers:
method creates a deep clone of a given value using the structured clone algorithm.
const clone = structuredClone(object);

Remove the object of a specific index in a JSON array without leaving "null" behind (Node.js)

I have a local JSON file under the path static/json/test.json. Its content is [{"id": 12}, {"id": 44}]. I want to read it, delete the object of the index i from it and rewrite the file so if for example i = 0 the new content should be [{"id": 44}].
What i have tried so far:
let i = 0;
fs.readFile("static/json/test.json", "utf8", function(err, data) {
let obj = JSON.parse(data); // obj is now [{"id": 12}, {"id": 44}]
delete obj[i];
fs.writeFile("static/json/test.json", JSON.stringify(obj), "utf8");
// test.json should now be [{"id": 44}], but its [null, {"id": 44}]
});
If I do this, the content of test.json isn't [{"id": 44}], it's [null, {"id": 44}].
I've read about using obj.splice(i, 1); instead of delete obj[i];, but for some reason that doesnt do anything, without me recieving any errors.
How do I remove the object of index i of this JSON array without leaving null behind?
Edit:
Thanks for the fast answers! Typically obj.splice(i, 1); should work, the cause why it doesn't for me has to have to do with my setup. The working answer for me is
let i = 0;
fs.readFile("static/json/test.json", "utf8", function(err, data) {
let obj = JSON.parse(data); // obj is now [{"id": 12}, {"id": 44}]
delete obj[i];
obj = obj.filter(item => item);
fs.writeFile("static/json/test.json", JSON.stringify(obj), "utf8");
// test.json is now [{"id": 44}]
});
You can do delete and filter out undefined
const obj= [{"id": 12}, {"id": 44}]
delete obj[0];
console.log(obj.filter(item => item));
BUT splice() works OK
const obj= [{"id": 12}, {"id": 44}]
obj.splice(0, 1);
console.log(obj);
You can use Array.splice to do this
// The item index to remove
let index = 0;
let arr = [{id: 12}, {id: 44}];
arr.splice(index,1);
console.log("Array after removing item", arr);

Javascript array includes

I'm trying to figure out if a array contains a specific index or not using the following codelines:
var array1 = [{ "abc": 123, "def": [{"a": 1, "b": 2, "c": 3}, {"a": 3, "b": 2, "c": 1}]}]
console.log(array1.includes('def'));
The array contains "def" so the console should actually return true if I define the array in the following way:
var array1 = [{ "abc": 123, "def": [{"a": 1, "b": 2, "c": 3}, {"a": 3, "b": 2, "c": 1}]}]
Defining it the other way, like:
var array1 = [{ "abc": 123 }]
should return false.
The code above therefore does not work correctly, does anyone have a idea whats causing it to respond a wrong boolean?
I appreciate any kind of suggestions!
The proper method would be array1.some(n => n.hasOwnProperty('def')). See that there is no def in array, but rather object that contains def property
Array.includes returns a boolean based on whether (x) is a value in the given Array, not keys. If you want array1.includes('def') to return the other parts then you must do Object.keys(array1[0]).includes('def')
That is because you do not indicate array you think of.
If you console.log
Object.getOwnPropertyNames(array1), array1 is an array of one object. To get proper result you have to check if the object inside have the def property, so:
array1[0].hasOwnProperty('def') // returns true
The problem here is you try to access an element that is in an object and this object is in a list. To acces the list element, you need to specify its index (here 0). Then you can access the object keys with Object.keys.
var array1 = [{ "abc": 123, "def": [{"a": 1, "b": 2, "c": 3}, {"a": 3, "b": 2, "c": 1}]}]
Object.keys(array1[0]).forEach((element) => {
if(element === "def") console.log(true);
})

Access Variable in JS Array

I have the following object
var object = ["{
"a": "foo",
"b": "bar",
"c": "baz"
}
"]
I am interested in getting value a, but everything I have tried comes up undefined. I have tried object.a, object[0].a and object[a], I know it's something silly I am simply forgetting. Any help is greatly appreciated.
var object = ['{ "a": "foo", "b": "bar", "c": "baz" }'];
console.log(JSON.parse(object[0]).a);
your array should look like this
var object = [{
"a": "foo",
"b": "bar",
"c": "baz"
}];
remove the double quotes so that you can access the object inside the array or else you can use the JSON.parse() just like #Daniel did

sorting an orderedMap by a specific key in Immutable.js

Please check this fiddle example
How can I sort an orderedMap object by the keys sequence in a descending order? I know there is a sortBy method but the document doesn't give a clearer example.
Here's my original object:
var props = {
"item": {
"A": {
"sequence": 5
},
"B": {
"sequence": null
},
"C":{
"sequence": 2
}
}
}
I'd like the result to be like:
var props = {
"item": {
"A": {
"sequence": 5
},
"C":{
"sequence": 2
},
"B": {
"sequence": null
}
}
}
Example Code:
var data = Immutable.fromJS(props,(key, value)=>{
var isIndexed = Immutable.Iterable.isIndexed(value);
return isIndexed ? value.toList() :value.toOrderedMap();
});
var sorted = data.get('item').sortBy((item) => item.get('sequence'));
console.log(sorted.toJS())
The function you are providing to sortBy() is comparator and it needs to return a Number. By adding a minus in front of the item.get('sequence') or following the result with reverse() you will reverse the sort, getting you the output that you want.
Here's an example:
var sorted = data.get('item').sortBy((item) => -item.get('sequence'));
// or var sorted = data.get('item').sortBy((item) => item.get('sequence')).reverse();
// you can now use .map() to go through your OrderedMap which has been
// sortbed by the sequence property and would look like your desired output
Note that you are working with an OrderedMap and that simply calling sorted.toJS() would return a regular JS object where the keys are, obviously, not sorted.
// If you need to iterate through the map and return some
// plain JS you can do something like:
sorted.map(x => x.get('sequence')).toJS()
// => Object {A: 5, C: 2, B: null}

Categories