Related
I have a this type of a json object.
{
"id": "001",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001"],
"children": [
{
"id": "002",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "002"],
"children": []
},
{
"id": "003",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "003"],
"children": [
{
"id": "00001",
"type": "B",
"children": []
}
]
},
{
"id": "004",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "004"],
"children": [
{
"id": "005",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "004", "005"],
"children": []
},{
"id": "005",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "004", "005"],
"children": [
{
"id": "00002",
"type": "B",
"children": []
}
]
}
]
},
{
"id": "00003",
"type": "B",
"children": []
}
]
}
I need to replace all the object which is type: "B" , with this (which is mentioned below) type of object which I can get from an object with ids as keys of typed B. This typed B objects can be nested anywhere either as a first child or fifth child of a nested arrays of children
{
"id": "002",
"type": "A",
"value": "aaaaa",
"data:": {},
"children": []
},
How can I do that? This can be deeply nested and there's no specific place where we should replace the objects, beforehand. So, I need to go through the entire object and do that. How should I get it done?
EDIT
I updated the code in the question slightly. There's a path property of the nested in each object, except for typed B objects. So, when replacing the typed B properties with the other object, I need to add the paths in there as well.
eg: path for id: "00001", typed B object should be : ["001", "003", "00001"]
EDIT :
Expected result
{
"id": "001",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001"],
"children": [
{
"id": "002",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "002"],
"children": []
},
{
"id": "003",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "003"],
"children": [
{
"id": "002",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "003", "002"],
"children": []
},
]
},
{
"id": "004",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "004"],
"children": [
{
"id": "005",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "004", "005"],
"children": []
},{
"id": "005",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "004", "005"],
"children": [
{
"id": "002",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "004", "005", "002"],
"children": []
}
]
}
]
},
{
"id": "002",
"type": "A",
"value": "aaaaa",
"data:": {},
"path": ["001", "002"],
"children": []
}
]
}
lodash if you don't mind.
Use cloneDeepWith to clone the entire tree and replace a specific value.
const data = {"id":"001","type":"A","value":"aaaaa","data:":{},"children":[{"id":"002","type":"A","value":"aaaaa","data:":{},"children":[]},{"id":"003","type":"A","value":"aaaaa","data:":{},"children":[{"id":"00001","type":"B","children":[]}]},{"id":"004","type":"A","value":"aaaaa","data:":{},"children":[{"id":"005","type":"A","value":"aaaaa","data:":{},"children":[]},{"id":"005","type":"A","value":"aaaaa","data:":{},"children":[{"id":"00002","type":"B","children":[]}]}]},{"id":"00003","type":"B","children":[]}]};
const result = _.cloneDeepWith(data, (value) => {
const newObj = {"id": "002", "type": "A", "value": "---NEW VALUE FOR 'B' TYPE---", "data:": {} };
return (value.type === 'B') ? { ...value, ...newObj} : _.noop();
});
console.dir(result, { depth: null } );
.as-console-wrapper{min-height: 100%!important; top: 0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.js" integrity="sha512-2iwCHjuj+PmdCyvb88rMOch0UcKQxVHi/gsAml1fN3eg82IDaO/cdzzeXX4iF2VzIIes7pODE1/G0ts3QBwslA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
--- Update 2--- (Without lodash)
Use local variable to store and combine current path.
const data = { "id": "001", "type": "A", "value": "aaaaa", "data:": {}, "path": ["001"], "children": [{ "id": "002", "type": "A", "value": "aaaaa", "data:": {}, "path": ["001", "002"], "children": [] }, { "id": "003", "type": "A", "value": "aaaaa", "data:": {}, "path": ["001", "003"], "children": [{ "id": "00001", "type": "B", "children": [] }] }, { "id": "004", "type": "A", "value": "aaaaa", "data:": {}, "path": ["001", "004"], "children": [{ "id": "005", "type": "A", "value": "aaaaa", "data:": {}, "path": ["001", "004", "005"], "children": [] }, { "id": "005", "type": "A", "value": "aaaaa", "data:": {}, "path": ["001", "004", "005"], "children": [{ "id": "00002", "type": "B", "children": [] }] }] }, { "id": "00003", "type": "B", "children": [] }] }
const deepReplace = (obj, prevPath = []) => {
if (obj.type === 'A') {
if (obj.children.length) {
obj.children = obj.children.map((childObj) => deepReplace(childObj, obj.path))
}
return obj;
};
if (obj.type === 'B') {
const id = '002';
return { id, type: "A", value: "aaaaa", path: [...prevPath, id], data: {}, children: []};
};
};
console.dir(deepReplace(data), { depth: null });
.as-console-wrapper{min-height: 100%!important; top: 0}
This looks like a tree traversal problem. Here's a way to handle that with depth-first search without recursion.
As mentioned in this answer, recursion should be avoided whenever possible, as it requires more memory and is more difficult to debug than an iterative implementation.
Updated per adjustment in question
const data = {"id":"001","type":"A","value":"aaaaa","data:":{},"path":["001"],"children":[{"id":"002","type":"A","value":"aaaaa","data:":{},"path":["001","002"],"children":[]},{"id":"003","type":"A","value":"aaaaa","data:":{},"path":["001","003"],"children":[{"id":"00001","type":"B","children":[]}]},{"id":"004","type":"A","value":"aaaaa","data:":{},"path":["001","004"],"children":[{"id":"005","type":"A","value":"aaaaa","data:":{},"path":["001","004","005"],"children":[]},{"id":"005","type":"A","value":"aaaaa","data:":{},"path":["001","004","005"],"children":[{"id":"00002","type":"B","children":[]}]}]},{"id":"00003","type":"B","children":[]}]};
const dfs = () => {
const stack = [[data, null]];
while(stack.length) {
const [curr, parent] = stack.pop();
// check for match on type
if (curr.type === "B") {
curr.type = "A";
curr.id = "002";
curr.value = "aaaaa";
curr.data = {};
curr.path = [...parent?.path.slice() ?? [], "002"];
}
curr.children.forEach(child => stack.push([child, curr]));
}
};
dfs();
const output = document.getElementById("output");
output.innerText = JSON.stringify(data, null, 2);
<pre id="output" />
I played around with this in the console and it did what you wanted (based on the json array provided, setting all the "B" to "A" types). It's a recursive function so on any nested child it meets in the "children" array it would call the function again on each item in the array.
function fixObjects (obj) {
if (obj["type"] === "B") {
obj["type"] = "A";
obj["id"] = "002";
obj["value"] = "aaaaa";
obj["data"] = {};
}
if (obj["children"].length > 0) {
obj["children"].forEach (child => fixObjects (child));
}
}
fixObjects (_yourArray)
I am converting the object to tree node format using the below method
function getNodes(object) {
return Object
.entries(object)
.map(([key, value]) => value && typeof value === 'object' ?
{
value: key + value,
label: key,
children: getNodes(value)
} :
{
value: key + value,
label: key
}
);
}
The sample object is:
var object = {
"income-array": [{
"income": {
"id": "1234",
"currency": "dollar",
"details": {
"individual-income": [{
"name": "abcd",
"income": 100
}, {
"name": "xyz",
"income": 500
}]
}
}
}]
}
I am getting this result:
[{
"value": "income-array[object Object]",
"label": "income-array",
"children": [{
"value": "0[object Object]",
"label": "0",
"children": [{
"value": "income[object Object]",
"label": "income",
"children": [{
"value": "id1234",
"label": "id"
}, {
"value": "currencydollar",
"label": "currency"
}, {
"value": "details[object Object]",
"label": "details",
"children": [{
"value": "individual-income[object Object],[object Object]",
"label": "individual-income",
"children": [{
"value": "0[object Object]",
"label": "0",
"children": [{
"value": "nameabcd",
"label": "name"
}, {
"value": "income100",
"label": "income"
}]
}, {
"value": "1[object Object]",
"label": "1",
"children": [{
"value": "namexyz",
"label": "name"
}, {
"value": "income500",
"label": "income"
}]
}]
}]
}]
}]
}]
}]
I want to get the value property path from root to a particular node like the below. I am confused with how to append step by step path to value.
[{
"value": "income-array",
"label": "income-array",
"children": [{
"value": "['income-array'][0]",
"label": "0",
"children": [{
"value": "['income-array'][0]['income']",
"label": "income",
"children": [{
"value": "['income-array'][0]['income']['id']",
"label": "id"
}, {
"value": "['income-array'][0]['income']['currencydollar']",
"label": "currency"
}, {
"value": "['income-array'][0]['income']['details']",
"label": "details",
"children": [{
"value": "['income-array'][0]['income']['details']['individual-income']",
"label": "individual-income",
"children": [{
"value": "['income-array'][0]['income']['details']['individual-income'][0]",
"label": "0",
"children": [{
"value": "['income-array'][0]['income']['details']['individual-income'][0]['name']",
"label": "name"
}, {
"value": "['income-array'][0]['income']['details']['individual-income'][0]['income']",
"label": "income"
}]
}, {
"value": "['income-array'][0]['income']['details']['individual-income'][1]",
"label": "1",
"children": [{
"value": "['income-array'][0]['income']['details']['individual-income'][1]['name']",
"label": "name"
}, {
"value": "['income-array'][0]['income']['details']['individual-income'][1]['income']",
"label": "income"
}]
}]
}]
}]
}]
}]
}]
Can you please guide me how to resolve this? Thanks
The outer function needs to pass its own current absolute path (which is value in your code) to the inner function,
in order to let the inner function know the previous paths.
Notice the parentPath='' parameter and children: getNodes(value, currentPath) below
function getNodes(object, parentPath = "") {
return Object.entries(object).map(([key, value]) => {
const currentPath = parentPath + `[${key}]`;
return value && typeof value === "object"
? {
value: currentPath,
label: key,
children: getNodes(value, currentPath),
}
: {
value: currentPath,
label: key,
};
});
}
After that, run getNodes(object) in the browser and you will get a result like this.
[
{
"value": "[income-array]",
"label": "income-array",
"children": [
{
"value": "[income-array][0]",
"label": "0",
"children": [
{
"value": "[income-array][0][income]",
"label": "income",
"children": [
{
"value": "[income-array][0][income][id]",
"label": "id"
},
{
"value": "[income-array][0][income][currency]",
"label": "currency"
},
{
"value": "[income-array][0][income][details]",
"label": "details",
"children": [
{
"value": "[income-array][0][income][details][individual-income]",
"label": "individual-income",
"children": [
{
"value": "[income-array][0][income][details][individual-income][0]",
"label": "0",
"children": [
{
"value": "[income-array][0][income][details][individual-income][0][name]",
"label": "name"
},
{
"value": "[income-array][0][income][details][individual-income][0][income]",
"label": "income"
}
]
},
{
"value": "[income-array][0][income][details][individual-income][1]",
"label": "1",
"children": [
{
"value": "[income-array][0][income][details][individual-income][1][name]",
"label": "name"
},
{
"value": "[income-array][0][income][details][individual-income][1][income]",
"label": "income"
}
]
}
]
}
]
}
]
}
]
}
]
}
]
how to merge the keys in the array into a single key with using the seperator, if value is null dont take it
let keysToBeMerged = [['note', 'status', seperator: ' ,'], ['group', 'level', seperator: ' ()']];
let data = [
{
"fields": [
{
"key": "area",
"value": null
},
{
"key": "terminal",
"value": null
},
{
"key": "note",
"value": "Some key notes"
},
{
"key": "status",
"value": "Enabled"
},
{
"key": "group",
"value": "Medium"
},
{
"key": "level",
"value": null
}
],
"name": "test 1",
"number": "123456127890",
"id": "yqweyqweu213"
},
{
"fields": [
{
"key": "area",
"value": "Delhi"
},
{
"key": "terminal",
"value": null
},
{
"key": "note",
"value": "Some key orginal notes"
},
{
"key": "status",
"value": "Disabled"
},
{
"key": "group",
"value": "Medium"
},
{
"key": "level",
"value": "High"
}
],
"name": "test 2",
"number": "173276123612",
"id": "uqweyewueyyuqwe"
},
{
"fields": [
{
"key": "area",
"value": "Mumbai"
},
{
"key": "terminal",
"value": 1
},
{
"key": "note",
"value": "Some key orginal sample notes"
},
{
"key": "status",
"value": "Enabled"
},
{
"key": "group",
"value": "Low"
},
{
"key": "level",
"value": null
}
],
"name": "test 3",
"number": "128737812381723",
"id": "kasjdashdkaskjd"
}
]
i have a collection called keysToBeMerged, i need to find the key from the he fields collection and need to merge some keys into a single key with merged values with using the seperator.
tried with below snippet
data.map(o => {
let key = []
let value = []
o.fields.forEach(f => {
keysToBeMerged.forEach(kColl => {
if(kColl.includes(f.key)){
key.push(f.key)
value.push(f.value)
}
})
console.log(key.join(""))
console.log(value.join(""))
})
return o
})
the expectedResult is shown below. Any help appreciated
let expectedResult = [
{
"fields": [
{
"key": "area",
"value": null
},
{
"key": "terminal",
"value": null
},
{
"key": "note|status",
"value": "Some key notes, Enabled"
},
{
"key": "group|level",
"value": "Medium"
}
],
"name": "test 1",
"number": "123456127890",
"id": "yqweyqweu213"
},
{
"fields": [
{
"key": "area",
"value": "Delhi"
},
{
"key": "terminal",
"value": null
},
{
"key": "note|status",
"value": "Some key orginal notes, Disabled"
},
{
"key": "group|level",
"value": "Medium (High)"
},
],
"name": "test 2",
"number": "173276123612",
"id": "uqweyewueyyuqwe"
},
{
"fields": [
{
"key": "area",
"value": "Mumbai"
},
{
"key": "terminal",
"value": 1
},
{
"key": "note|status",
"value": "Some key orginal sample notes, Enabled"
},
{
"key": "group|level",
"value": "Low"
},
],
"name": "test 3",
"number": "128737812381723",
"id": "kasjdashdkaskjd"
}
]
I have hundreds of objects inside each other
and under each object there is a repeated object structure with an object inside that contains hundred of keys that are the same and in most of the keys the values are the same also.
What I would like to do is to get from this repeated object the key and value only if its the same across all over the objects and put it aside in an new object that contains all the same repeated pairs of key/value while also remove it from that repeated object inside of every one of the objects.
json objects for example:
[{
"name": "A",
"values": {
"ab": "abc",
"ac": "1",
"ad": "none"
},
"childs": []
},
{
"name": "A",
"values": {
"ab": "abc",
"ac": "1",
"ad": "none"
},
"childs": [{
"name": "B",
"values": {
"ab": "abc",
"ac": "1",
"ad": "none"
},
"childs": [{
"name": "C",
"values": {
"ab": "abc",
"ac": "1",
"ad": "none"
},
"childs": []
},
{
"name": "C",
"values": {
"ab": "def",
"ac": "1",
"ad": "none"
},
"childs": []
}
]
}]
},
{
"name": "A",
"values": {
"ab": "abc",
"ac": "1",
"ad": "none"
},
"childs": [{
"name": "D",
"values": {
"ab": "abc",
"ac": "1",
"ad": "none"
},
"childs": []
}]
}]
desired output:
[{
"name": "A",
"values": {
"ab": "abc"
},
"childs": []
},
{
"name": "A",
"values": {
"ab": "abc"
},
"childs": [{
"name": "B",
"values": {
"ab": "abc"
},
"childs": [{
"name": "C",
"values": {
"ab": "abc"
},
"childs": []
},
{
"name": "C",
"values": {
"ab": "def"
},
"childs": []
}
]
}]
},
{
"name": "A",
"values": {
"ab": "abc"
},
"childs": [{
"name": "D",
"values": {
"ab": "abc"
},
"childs": []
}]
}]
and a new object contains the key/value pairs that were removed because they are the same:
[{
"ac": "1",
"ad": "none"
}]
We could take the first object as a starting point for key value pairs:
let pairs = Object.entries( objects[0].values );
Then for all the values we remove non dupes:
function remove(obj){
pairs = pairs.filter(([key,value]) => obj.values[key] === value);
//the same for all childs:
if(obj.childs) obj.childs.forEach(remove);
}
objects.forEach(remove);
So now weve got a list of key values every object shares, so now we can build an object again:
const result = {};
for(let [key,value] of pairs) result[key] = value;
And we can remove duplicates:
function dupes(obj){
pairs.forEach(([key]) => {
if( key in obj.values) delete obj.values[key];
});
if(obj.childs) obj.childs.forEach(dupes);
}
objects.forEach(dupes)
Try it
I have two variables array1 and array2 as following and I want to put the values of array2 into array1 for the properties present in array1 and rest of the properties should remain the same with default values.
One solution I have is to iterate through the array length and set values for found properties and but my array is too long to perform iteration (the array supplied in this question is just a raw value).
I need some better way other than iteration.
var array1=[
{
"name": "a",
"value": 0,
"level": [
{
"name": "a1",
"value": 0
},
{
"name": "a2",
"value": 0
}
]
},
{
"name": "b",
"value": 0,
"level": [
{
"name": "b1",
"value": 0
},
{
"name": "b2",
"value": 0
}
]
},
{
"name": "c",
"value": 0,
"level": [
{
"name": "c1",
"value": 0
},
{
"name": "c2",
"value": 0
}
]
}
]
var array2=[
{
"name": "a",
"value": 1,
"level": [
{
"name": "a1",
"value": 1
},
{
"name": "a2",
"value": 0
}
]
},
{
"name": "b",
"value": 1,
"level": [
{
"name": "b1",
"value": 0
},
{
"name": "b2",
"value": 1
}
]
}
]
and the required output is
var final_array=[
{
"name": "a",
"value": 1,
"level": [
{
"name": "a1",
"value": 1
},
{
"name": "a2",
"value": 0
}
]
},
{
"name": "b",
"value": 1,
"level": [
{
"name": "b1",
"value": 0
},
{
"name": "b2",
"value": 1
}
]
},
{
"name": "c",
"value": 0,
"level": [
{
"name": "c1",
"value": 0
},
{
"name": "c2",
"value": 0
}
]
}
]
A recursive solution with two iterators, one for arrays iterateA and one for objects iterateO. This proposal uses the thisArg for reference to json2.
Basically both callbacks iterates over the items or keys and checks if this is set and if the actual item is present in this. if not, the function returns.
The rest is straight forward, if an object is found, then it iterates over the keys and the object, if an array is found, the it it iterates over the array.
Only in the case of k === 'value' the value of this[k] is to o[k] assigned.
var json1 = [{ "name": "a", "value": 0, "level": [{ "name": "a1", "value": 0 }, { "name": "a2", "value": 0 }] }, { "name": "b", "value": 0, "level": [{ "name": "b1", "value": 0 }, { "name": "b2", "value": 0 }] }, { "name": "c", "value": 0, "level": [{ "name": "c1", "value": 0 }, { "name": "c2", "value": 0 }] }],
json2 = [{ "name": "a", "value": 1, "level": [{ "name": "a1", "value": 1 }, { "name": "a2", "value": 0 }] }, { "name": "b", "value": 1, "level": [{ "name": "b1", "value": 0 }, { "name": "b2", "value": 1 }] }];
function iterateO(o) {
return function (k) {
if (!this || !(k in this)) {
return;
}
if (typeof o[k] === 'object') {
Object.keys(o[k]).forEach(iterateO(o[k]), this[k]);
return;
}
if (Array.isArray(o[k])) {
o[k].forEach(iterateA, this[k]);
return;
}
if (k === 'value') {
o[k] = this[k];
}
};
}
function iterateA(a, i, aa) {
if (!this || !(i in this)) {
return;
}
if (typeof a === 'object') {
Object.keys(a).forEach(iterateO(a), this[i]);
return;
}
if (Array.isArray(a)) {
a.forEach(iterateA, this[i]);
return;
}
}
json1.forEach(iterateA, json2);
document.write('<pre>' + JSON.stringify(json1, 0, 4) + '</pre>');