RXJS, add new key:value to nested observable - javascript

I'm new with rxjs and i can't see how can i do what i need. I need to add a pair active:true recursively.
I have this data structure coming from api as observable:
var data = [
{
name: "hom",
subcategories: [
{ name: "reb" },
{ name: "nov" },
{ name: "otr" }
]
},
{
name: "muj",
subcategories: [
{ name: "REB" },
{ name: "NOV" },
{ name: "OT" }
]
},
{
name: "ni",
subcategories: [
{ name: "REB", subcategories: [
{name: "rebanis"},
{name: "rebawos"}] },
{ name: "NOV", subcategories: [
{name: "novebanis"},
{name: "novrebawos"}] },
{ name: "OT", subcategories: [
{name: "otrebanis"},
{name: "otrebawos"}]
}
]
}
];
And what i want is to add a active:true on every level that have subcategories, and i don't know how many nested subcategories could be.
This is the result that i want:
var data = [
{
active: true,
name: "hom",
subcategories: [
{ name: "reb" },
{ name: "nov" },
{ name: "otr" }
]
},
{
active: true,
name: "muj",
subcategories: [
{ name: "REB" },
{ name: "NOV" },
{ name: "OT" }
]
},
{
name: "ni",
active: true,
subcategories: [
{ name: "REB", active: true, subcategories: [
{name: "rebanis"},
{name: "rebawos"}] },
{ name: "NOV", active: true, subcategories: [
{name: "novebanis"},
{name: "novrebawos"}] },
{ name: "OT", active: true, subcategories: [
{name: "otrebanis"},
{name: "otrebawos"}]
}
]
}
];
I tried something like this:
const req = of(data)
.pipe(
map(data => {
const transformedData = Object.keys(data).map(key =>
Object.assign(data[key], { active: true })
);
return transformedData;
})
)
.subscribe(output => console.log(output));
But the result is not clear and it only affects on first level not on nested.

You can use map inside recursive function:
const data = [ { name: "hom", subcategories: [ { name: "reb" }, { name: "nov" }, { name: "otr" } ] }, { name: "muj", subcategories: [ { name: "REB" }, { name: "NOV" }, { name: "OT" } ] }, { name: "ni", subcategories: [ { name: "REB", subcategories: [ {name: "rebanis"}, {name: "rebawos"}] }, { name: "NOV", subcategories: [ {name: "novebanis"}, {name: "novrebawos"}] }, { name: "OT", subcategories: [ {name: "otrebanis"}, {name: "otrebawos"}] } ] } ];
const addNewProp=data=>data.map(o=>o.subcategories ? ({...o, active:true, subcategories: addNewProp(o.subcategories)}) : o);
console.log(addNewProp(data));

The question has nothing to do with rxJs and Observable, it is a problem of transformation of an Array.
I would try something like this
data.map(el => {
if(el.subcategories && el.subcategories.lenght > 0) {
const newEl = {...el};
newEl.active = true;
return newEl;
}
return {...el}
})
Notice that here I am using some sort of immutability and hence I create new elements within the loop. If this is not required in your case, you can simplify the code like this
data.map(el => {
if(el.subcategories && el.subcategories.lenght > 0) {
el.active = true;
}
return el
})

Related

search an item in multidimentionnal array

I'm trying to find an element on a multidimentionnal array usin JAVASCRIPT function, but I get error
This is my array's data:
export const datas = [
{
id: 1,
firstName: 'John',
tables: [
{ ID: 11, title: 'Lorem' },
{ ID: 12, title: 'Ipsum' },
],
},
{
id: 2,
firstName: 'Doe',
tables: [
{
ID: 22,
title: 'Arke',
nodes: [{ name: 'Name1' }, { name: 'Name2' }, { name: 'Name3' }],
},
{ ID: 23, title: 'Korem' },
],
},
{
id: 3,
firstName: 'Brad',
tables: [
{
ID: 30,
title: 'Mern',
nodes: [{ name: 'Name4' }, { name: 'Name5' }, { name: 'Name6' }],
},
{
ID: 31,
title: 'Full',
nodes: [{ name: 'Name7' }, { name: 'Name8' }, { name: 'Name9' }],
},
],
},
];
I've tried a reccursive function but it's not work, this is my code :
export const findById = (arr, id) => {
for (let o of arr) {
if (o.tables.length > 0) {
let a = findById(o.tables.nodes, 'id');
console.log(a);
}
}
};
I want to print the Object with ID 22, the problem is that I don't have the same structure in each dimension, and it still confuse me..
My Input : 22
My output :
{
ID: 22,
title: 'Arke',
nodes: [{ name: 'Name1' }, { name: 'Name2' }, { name: 'Name3' }],
},
Have you an idea how to edit my function to get my input's response ?
Your recursive function wasn't too far off, you need to check if the item as a tables first before recursively calling it again. And then finally just check the ID in the loop.
eg..
const datas=[{id:1,firstName:"John",tables:[{ID:11,title:"Lorem"},{ID:12,title:"Ipsum"}]},{id:2,firstName:"Doe",tables:[{ID:22,title:"Arke",nodes:[{name:"Name1"},{name:"Name2"},{name:"Name3"}]},{ID:23,title:"Korem"}]},{id:3,firstName:"Brad",tables:[{ID:30,title:"Mern",nodes:[{name:"Name4"},{name:"Name5"},{name:"Name6"}]},{ID:31,title:"Full",nodes:[{name:"Name7"},{name:"Name8"},{name:"Name9"}]}]}];
function findById(arr, ID) {
for (const a of arr) {
if (a.tables) {
const r = findById(a.tables, ID);
if (r) return r;
}
if (a.ID === ID) return a;
}
}
console.log(findById(datas, 22));
if you just need the nested data you can use flatMap and find
const findById = (arr, id) =>
arr
.flatMap(d => d.tables)
.find(t => t.ID === id)
const datas = [{
id: 1,
firstName: 'John',
tables: [{
ID: 11,
title: 'Lorem'
},
{
ID: 12,
title: 'Ipsum'
},
],
},
{
id: 2,
firstName: 'Doe',
tables: [{
ID: 22,
title: 'Arke',
nodes: [{
name: 'Name1'
}, {
name: 'Name2'
}, {
name: 'Name3'
}],
},
{
ID: 23,
title: 'Korem'
},
],
},
{
id: 3,
firstName: 'Brad',
tables: [{
ID: 30,
title: 'Mern',
nodes: [{
name: 'Name4'
}, {
name: 'Name5'
}, {
name: 'Name6'
}],
},
{
ID: 31,
title: 'Full',
nodes: [{
name: 'Name7'
}, {
name: 'Name8'
}, {
name: 'Name9'
}],
},
],
},
];
console.log(findById(datas, 22))
js has amazing array options https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
the ones which will help you most are probably:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flatMap
here are some examples
// get the base with id 22
const baseWith22ID = datas.filter(f => f.tables.filter(s => s.id = 22))
// (i guess you want this one) get all elements with id 22
const onlyElementsWith22ID = datas.flatMap(f => f.tables.filter(s => s.id = 22))

How do I map through a variable in React JS

I was using react-tree-graph and I was creating a data object but I want to use my backend api to fill in the properties of the data object. I tried using the .map method to loop through my api but I couldnt figure out how to get it to work. Here's the data object and below is my object from my api.
let data = {
name: 'Water',
children: [
{
name: 'Earth',
children: [
{
name: 'Air',
children: [
{
name: 'Fire',
children: [],
},
{
name: 'Fire2',
children: [],
},
],
},
{
name: 'Air2',
children: [
{
name: 'Fire3',
children: [],
},
{
name: 'Fire4',
children: [],
},
],
},
],
},
{
name: 'Earth2',
children: [
{
name: 'Air3',
children: [
{
name: 'Fire5',
children: [],
},
{
name: 'Fire6',
children: [],
},
],
},
{
name: 'Air4',
children: [
{
name: 'Fire7',
children: [],
},
{
name: 'Fire8',
children: [],
},
],
},
],
},
],
};
Instead of the strings I want to map through this variable and fill it in with object as such
flower= {water: "name1",air: "name2",air2: "name3",air3: "name4",air4: "name5",earth: "name6",earth2: "name7",fire: "name8",fire2: "name9",fire3: "name10",fire4: "name11",fire5: "name12",fire6: "name13",fire7: "name14",fire8: "name15"}
I just wanted to know how I could use this object and map through it to fill in the different properties inside the data object
Here is a solution for you question, Ive worked with recursive.
let data = {
name: 'Water',
children: [
{
name: 'Earth',
children: [
{
name: 'Air',
children: [
{
name: 'Fire',
children: [],
},
{
name: 'Fire2',
children: [],
},
],
},
{
name: 'Air2',
children: [
{
name: 'Fire3',
children: [],
},
{
name: 'Fire4',
children: [],
},
],
},
],
},
{
name: 'Earth2',
children: [
{
name: 'Air3',
children: [
{
name: 'Fire5',
children: [],
},
{
name: 'Fire6',
children: [],
},
],
},
{
name: 'Air4',
children: [
{
name: 'Fire7',
children: [],
},
{
name: 'Fire8',
children: [],
},
],
},
],
},
],
};
let counter = 1;
function recursiveNaming(data) {
return data.children.reduce((acc, curr) => {
let obj;
let currentObj = {...acc, [curr.name]:`name${counter++}`};
if(curr.children.length) {
obj = recursiveNaming(curr);
}
return {...currentObj, ...obj };
},{})
};
console.log(recursiveNaming(data))
Hope it worth it....

An array of objects with each individual child of this object

i Have enteried JS object like this:
const arr = [
{
name: 'obj-1',
children: [
{
name: 'obj-1-child1',
children: [
{
name: 'obj-1-child1-child1',
children: [
{
name: 'obj-1-child1-child1-child1'
},
{
name: 'obj-1-child1-child1-child2'
}
]
},
{
name: 'obj-1-child1-child2'
}
]
},
{
name: 'obj-1-child1',
children: [
{
name: 'obj-1-child2-child1',
children: [
{
name: 'obj-1-child2-child1-child1'
}
]
}
]
}
]
},
{
name: 'obj-2',
children: [
{
name: 'obj-2-child1',
children: [
{
name: 'obj-2-child1-child1'
}
]
}
]
}
]
I tried to do it by iterating the object with a FOR loop.
A separate object is needed for each step of this tree. obj1->child1 then obj1->child1->child1 then obj1->child1->child1->child1 etc for each step for all elements in tree
const arr1 = [
{
name: 'obj-1',
children: [] // one object for 1 step in tree
},
{
name: 'obj-1',
children: [
{
name: 'obj-1-child1',
children: []
}
]
},
{
name: 'obj-1',
children: [
{
name: 'obj-1-child1',
children: [
{
name: 'obj-1-child1-child1',
children: []
}
]
}
]
},
{
name: 'obj-1',
children: [
{
name: 'obj-1-child1',
children: [
{
name: 'obj-1-child1-child1',
children: [
{
name: 'obj-1-child1-child1-child1'
}
]
}
]
}
]
}
]
which means for such a tree, the result should be: 12 elements

How to fetch data from complex array objects structures?

I have such an object
data: {
dataFirst: {
Food: [ {id: 536131, name: "option1", }]
},
dataSecond: {
Autos: [{id: 678, name: 'option1'}],
Houses: [
{id: 6876, name: "option1"},
{id: 6876, name: "Placed App"},
],
Phones: [
{id: 672, name: "option1"},
{id: 97249, name: "Placed},
],
Food: [
{id: 772, name: "option1"},
{id: 6777, name: "Placed},
],
}
}
The problem is, that I may have same data in dataFirst and dataSecond, for examle 'Food', I have 2 array objects that contains different data but I need to make it one object 'Food' with the data from 2 of them, from the dataFirst 'Food' and dataSecond 'Food'. I had such a code:
export const parser = ({ data }) => {
const result = Object.values(data).reduce((prev, topicsGroup) => {
Object.assign(prev, topicsGroup);
return prev;
}, {});
return result;
}
but this code doesn't unite 2 'Food' objects but returns data only from the dataFirst 'Food' object wihout second one.
You can iterate through all values of your main data object with Object.values(data) and combine them with reduce by concatenating arrays corresponding to common keys:
let data = {
dataFirst: {
Food: [{
id: 536131,
name: "option1",
}]
},
dataSecond: {
Autos: [{
topicId: 678,
name: 'option1'
}],
Houses: [{
topicId: 6876,
name: "option1"
},
{
topicId: 6876,
topicName: "Placed App"
},
],
Phones: [{
topicId: 672,
name: "option1"
},
{
topicId: 97249,
name: "Placed"
},
],
Food: [{
topicId: 772,
name: "option1"
},
{
topicId: 6777,
name: "Placed"
},
],
}
};
let res = Object.values(data).reduce((acc, curr) => {
Object.entries(curr).forEach(([k, v]) => {
if (k in acc) acc[k] = acc[k].concat(v);
else acc[k] = v;
});
return acc;
}, {});
console.log(res);

Return a set of documents with all sub-arrays containing a given value in loopback or nodejs

How do I return a set of documents that has sub-arrays that matches common values. To better explain, consider the following data:
[
{
Category: 1,
Products: [
{
Name: 'ABC',
ColorCode:[1,2,3,4,5]
},
{
Name: 'DEF',
ColorCode:[1,2,3,4,5,6]
},
{
Name: 'GHI',
ColorCode:[1,2,3,4,6,7]
}
]
},
{
Category: 2,
Products: [
{
Name: 'JKL',
ColorCode:[4,6,7,]
},
{
Name: 'MNO',
ColorCode:[4,5,6,9,]
}
]
},
{
Category: 3,
Products: [
{
Name: 'OPQ',
ColorCode:[3,4,5,6,9,10]
},
{
Name: 'RST',
ColorCode:[2,3,5,6,9,10]
}
]
}]
The task is,
Get all the Categories with all the products containing a specific color code:
For example,
For ColorCode = 6,
Result should be:
[
{
Category: 2,
Products: [
{
Name: 'JKL',
ColorCode:[4,6,7,]
},
{
Name: 'MNO',
ColorCode:[5,6,9,]
}
]
},
{
Category: 3,
Products: [
{
Name: 'OPQ',
ColorCode:[3,4,5,6,9,10]
},
{
Name: 'RST',
ColorCode:[2,3,5,6,9,10]
}
]
}]
For ColorCode = 4,
Result should be:
[
{
Category: 1,
Products: [
{
Name: 'ABC',
ColorCode:[1,2,3,4,5]
},
{
Name: 'DEF',
ColorCode:[1,2,3,4,5,6]
},
{
Name: 'GHI',
ColorCode:[1,2,3,4,6,7]
}
]
},
{
Category: 2,
Products: [
{
Name: 'JKL',
ColorCode:[4,6,7,]
},
{
Name: 'MNO',
ColorCode:[4,5,6,9,]
}
]
}]
For ColorCode = 7,
Result should be an empty array:
[]
Thanks in advance.
You're looking for Array.prototype.filter.
// filter out categories that don't contain color code 4
categories.filter(function(category) {
return category.products.filter(containsColor(4)) > 0;
});
function containsColor(colorCode) {
return function(product) {
return product.ColorCode.indexOf(colorCode) >= 0;
};
}

Categories

Resources