Flatten nested array of objects JS - javascript

I have a nested array of objects and want to get only the child property elements of an array. This is just an example and the actual data will include a unique children property in separate indices in the array. I am only able to traverse the first array in the list.
Here is my implementation:
const headers = [{
id: "name1",
title: "Name 1",
children: [{
title: "Children 1",
child: [{
title: "Child 1",
onClick: "child1Click"
},
{
title: "Child 2",
onClick: "child2Click"
}
]
},
{
title: "CHildren 2",
child: [{
title: "Child 3",
id: "child3Click"
},
{
title: "Child 4",
id: "child4Click"
}
]
}
]
},
{
id: "name2",
title: "Name 2",
children: [{
title: "Children 3",
child: [{
title: "Child 5",
onClick: "child5Click"
},
{
title: "Child 6",
onClick: "child6Click"
}
]
},
{
title: "CHildren 4",
child: [{
title: "Child 7",
id: "child7Click"
},
{
title: "Child 8",
id: "child8Click"
}
]
}
]
},
{
id: "name3",
title: "Name 3"
},
{
id: "name4",
title: "Name 4"
}
]
console.log(_.flattenDeep(_.map(_.compact(_.map(headers, item => item.children))[0], item1 => item1.child)))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
Expected Output:
[
{
"title": "Child 1",
"onClick": "child1Click"
},
{
"title": "Child 2",
"onClick": "child2Click"
},
{
"title": "Child 3",
"id": "child3Click"
},
{
"title": "Child 4",
"id": "child4Click"
},
{
"title": "Child 5",
"onClick": "child5Click"
},
{
"title": "Child 6",
"onClick": "child6Click"
},
{
"title": "Child 7",
"id": "child7Click"
},
{
"title": "Child 8",
"id": "child8Click"
}
]
Please advice.
Edit: I was able to get the required result using console.log(.flattenDeep(.map(.flattenDeep(.compact(_.map(headers, 'children'))), 'child')))
But is there an optimized version for doing the same? Thanks

Get the children with _.flatMap(), filter out the undefined values, and then use _.flatMap() again to get the values of the child property:
const headers = [{"id":"name1","title":"Name 1","children":[{"title":"Children 1","child":[{"title":"Child 1","onClick":"child1Click"},{"title":"Child 2","onClick":"child2Click"}]},{"title":"CHildren 2","child":[{"title":"Child 3","id":"child3Click"},{"title":"Child 4","id":"child4Click"}]}]},{"id":"name2","title":"Name 2","children":[{"title":"Children 3","child":[{"title":"Child 5","onClick":"child5Click"},{"title":"Child 6","onClick":"child6Click"}]},{"title":"CHildren 4","child":[{"title":"Child 7","id":"child7Click"},{"title":"Child 8","id":"child8Click"}]}]},{"id":"name3","title":"Name 3"},{"id":"name4","title":"Name 4"}]
const result = _.flatMap(_.compact(_.flatMap(headers, 'children')), 'child')
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
If you're using lodash/fp, you can generate a more readable function with _.flow():
const fn = _.flow(
_.flatMap('children'),
_.compact,
_.flatMap('child')
)
const headers = [{"id":"name1","title":"Name 1","children":[{"title":"Children 1","child":[{"title":"Child 1","onClick":"child1Click"},{"title":"Child 2","onClick":"child2Click"}]},{"title":"CHildren 2","child":[{"title":"Child 3","id":"child3Click"},{"title":"Child 4","id":"child4Click"}]}]},{"id":"name2","title":"Name 2","children":[{"title":"Children 3","child":[{"title":"Child 5","onClick":"child5Click"},{"title":"Child 6","onClick":"child6Click"}]},{"title":"CHildren 4","child":[{"title":"Child 7","id":"child7Click"},{"title":"Child 8","id":"child8Click"}]}]},{"id":"name3","title":"Name 3"},{"id":"name4","title":"Name 4"}]
const result = fn(headers)
console.log(result)
<script src='https://cdn.jsdelivr.net/g/lodash#4(lodash.min.js+lodash.fp.min.js)'></script>
Using lodash with _.flow() and _.partialRight():
const pr = _.partialRight;
const fn = _.flow(
pr(_.flatMap, 'children'),
_.compact,
pr(_.flatMap, 'child')
)
const headers = [{"id":"name1","title":"Name 1","children":[{"title":"Children 1","child":[{"title":"Child 1","onClick":"child1Click"},{"title":"Child 2","onClick":"child2Click"}]},{"title":"CHildren 2","child":[{"title":"Child 3","id":"child3Click"},{"title":"Child 4","id":"child4Click"}]}]},{"id":"name2","title":"Name 2","children":[{"title":"Children 3","child":[{"title":"Child 5","onClick":"child5Click"},{"title":"Child 6","onClick":"child6Click"}]},{"title":"CHildren 4","child":[{"title":"Child 7","id":"child7Click"},{"title":"Child 8","id":"child8Click"}]}]},{"id":"name3","title":"Name 3"},{"id":"name4","title":"Name 4"}]
const result = fn(headers)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>

Related

Recursively filter an array of infinitely nested objects by mutliple matching conditions but only return parent that has an instance of both matches

I have the following array of objects; however this could be any unknown key/value and be infinitely nested, for now this is a testing sample:
[
{
"reference_id": "R123",
"customer": "Person 1",
"customer_email": "person1#email.com",
"location": "UK",
"bookings": [
{
"product": "Product 1",
"provider": "Company 1",
"cancellable": true
},
{
"product": "Product 2",
"provider": "Company 2",
"cancellable": true
},
{
"product": "Product 3",
"provider": "Company 1",
"cancellable": true
}
]
},
{
"reference_id": "R1234",
"customer": "Person 2",
"customer_email": "person2#email.com",
"location": "USA",
"bookings": [
{
"product": "Product 1",
"provider": "Company 1",
"cancellable": true
},
{
"product": "Product 3",
"provider": "Company 1",
"cancellable": true
}
]
},
{
"reference_id": "R12345",
"customer": "Person 3",
"customer_email": "person3#email.com",
"location": "UK",
"bookings": [
{
"product": "Product 2",
"provider": "Company 2",
"cancellable": true
},
{
"product": "Product 3",
"provider": "Company 1",
"cancellable": true
}
]
}
]
My current implementation is as follows:
const selected = [
{
term: 'Company 1',
column: 'provider',
},
{
term: 'Person 1',
column: 'customer',
},
];
const recursivelyFilterByValue = () => (value) => selected.every((item) => {
if (!value) return false;
if (typeof value === 'string') {
// console.log('value', value === item.term);
return value === item.term;
}
if (Array.isArray(value)) {
return value.some(this.recursivelyFilterByValue());
}
if (typeof value === 'object') {
return Object.values(value).some(this.recursivelyFilterByValue());
}
return false;
});
const results = data.filter(recursivelyFilterByValue());
Basically I am adding to the "selected" array then using that to filter the data array by. I do want to ensure the key matches the "column" also however I haven't added that yet.
For the input above I would expect to output the below:
[
{
"reference_id": "R123",
"customer": "Person 1",
"customer_email": "person1#email.com",
"location": "UK",
"bookings": [
{
"product": "Product 1",
"provider": "Company 1",
"cancellable": true
},
{
"product": "Product 2",
"provider": "Company 2",
"cancellable": true
},
{
"product": "Product 3",
"provider": "Company 1",
"cancellable": true
}
]
},
]
However the output array is empty. If I only search for one term (remove all but one term from selected array) the output is correct for that term however any subsequent terms bring back a blank array.
I'm wondering if my use of .some() is the problem however changing this causes too much recursion errors.
Essentially, I want to return the original parent object so long as there is a key:value match for all my conditions in the selected array, at any level of its children.
Any guidance would be much appreciated, thank you.
I'm not quite sure if this is what you're looking for. It makes the assumption that my guess in the comments was correct:
Do I have this right? You have one (presumably dynamic) condition that says that an object either has a provider property with value "Customer 1" or has a (recursively) descendant object that does. And you have a second condition regarding customer and "Person 1", and you're looking for objects that meet both (or all) such conditions. Does that describe what you're trying to do?
Here we have two fairly simple helper functions, testRecursive and makePredicates as well as the main function, recursivelyFilterByValue:
const testRecursive = (pred) => (obj) =>
pred (obj) || Object (obj) === obj && Object .values (obj) .some (testRecursive (pred))
const makePredicates = (criteria) =>
criteria .map (({term, column}) => (v) => v [column] == term)
const recursivelyFilterByValue = (criteria, preds = makePredicates (criteria)) => (xs) =>
xs .filter (obj => preds .every (pred => testRecursive (pred) (obj)))
const selected = [{term: 'Company 1', column: 'provider'}, {term: 'Person 1', column: 'customer'}]
const input = [{reference_id: "R123", customer: "Person 1", customer_email: "person1#email.com", location: "UK", bookings: [{product: "Product 1", provider: "Company 1", cancellable: true}, {product: "Product 2", provider: "Company 2", cancellable: true}, {product: "Product 3", provider: "Company 1", cancellable: true}]}, {reference_id: "R1234", customer: "Person 2", customer_email: "person2#email.com", location: "USA", bookings: [{product: "Product 1", provider: "Company 1", cancellable: true}, {product: "Product 3", provider: "Company 1", cancellable: true}]}, {reference_id: "R12345", customer: "Person 3", customer_email: "person3#email.com", location: "UK", bookings: [{product: "Product 2", provider: "Company 2", cancellable: true}, {product: "Product 3", provider: "Company 1", cancellable: true}]}]
console .log (recursivelyFilterByValue (selected) (input))
.as-console-wrapper {max-height: 100% !important; top: 0}
testRecursive checks whether a predicate is true for an object or for any objects nested inside it.
makePredicates turns an array of {term, column}-objects into predicate functions that test if an object has the proper term in the property named by the column.
recursivelyFilterByValue combines these, calling makePredicates to turn the selected items into predicate functions, then filtering the input by testing if each of the predicates is true.
This is not the most efficient code imaginable. It rescans the hierarchy for each predicate. I'm sure we could figure out a version to do the scan only once, but I think it would make for much more complex code. So you might want to test in your production-sized data whether it's fast enough for your needs.
This solution is not as beautifully elegant as an accepted answer, but why not show my efforts. Perhaps someone will find this way more understandable.
const selected = [{term: 'Company 1', column: 'provider'}, {term: 'Person 1', column: 'customer'}]
const input = [{reference_id: "R123", customer: "Person 1", customer_email: "person1#email.com", location: "UK", bookings: [{product: "Product 1", provider: "Company 1", cancellable: true}, {product: "Product 2", provider: "Company 2", cancellable: true}, {product: "Product 3", provider: "Company 1", cancellable: true}]}, {reference_id: "R1234", customer: "Person 2", customer_email: "person2#email.com", location: "USA", bookings: [{product: "Product 1", provider: "Company 1", cancellable: true}, {product: "Product 3", provider: "Company 1", cancellable: true}]}, {reference_id: "R12345", customer: "Person 3", customer_email: "person3#email.com", location: "UK", bookings: [{product: "Product 2", provider: "Company 2", cancellable: true}, {product: "Product 3", provider: "Company 1", cancellable: true}]}]
const iter = (obj, sel) =>
Object.entries(obj).some(([key, value]) => {
if (Array.isArray(value))
return value.some((obj) => iter(obj, sel));
if (typeof value === 'object' && value !== null)
return iter(value, sel);
return (key === sel.column) && (value === sel.term);
});
const deepFilter = (arr, sels) =>
arr.filter((obj) =>
sels.every((sel) => iter(obj, sel)));
console.dir(deepFilter(input, selected), {depth: null});
.as-console-wrapper {max-height: 100% !important; top: 0}

Recursively Find and Add Them as an Array

I have this kind of table (or data structure)
There is parentIdeaId that refers to the id in ideas table itself.
Here's my unstructured data (please bear in mind this is the existing data in the database, not data that is already as it is so I have to query this first under some condition)
[{
"id": "1",
"title": "Title 1",
"parentIdeaId": null
},{
"id": "2",
"title": "Title 2",
"parentIdeaId": 1
},{
"id": "3",
"title": "Title 3",
"parentIdeaId": 2
},{
"id": "4",
"title": "Title 4",
"parentIdeaId": null
}]
I also made a function to find the data (I'm using Prisma in my real code)
function find({ id }) {
return prisma.idea.findUnique({
where: {
id
}
});
}
And a function to find the children
function responseIdeas({ parentIdeaId }) {
return prisma.idea.findMany({
where: {
parentIdeaId
}
});
}
I want the data to be filtered only linked data (by their parentIdeaId) so if I query the id "1" the result would be
[{
"id": "1",
"title": "Title 1",
"parentIdeaId": null
},{
"id": "2",
"title": "Title 2",
"parentIdeaId": 1
}{
"id": "3",
"title": "Title 3",
"parentIdeaId": 2
}]
The id: "4" isn't inserted because it's not related by its parent
Here's what I made:
const data = [
{
id: "1",
title: "Title 1",
parentIdeaId: null
},
{
id: "2",
title: "Title 2",
parentIdeaId: 1
},
{
id: "3",
title: "Title 3",
parentIdeaId: 2
},
{
id: "4",
title: "Title 4",
parentIdeaId: null
}
];
function find({ id }) {
return data.find(e => e.id === id);
}
function responseIdeas({ parentIdeaId }) {
return data.filter(e => e.parentIdeaId == parentIdeaId);
}
async function detail({ id }) {
const findChildren = async ({ id }) => {
const idea = await find({ id });
const responses = await responseIdeas({ parentIdeaId: id });
if (responses.length !== 0) {
const resolveResponses = await Promise.all(
responses.map(async ({ id }) => findChildren({ id }))
);
return [idea, ...resolveResponses];
}
return { ...idea };
};
return findChildren({ id });
}
async function run() {
const result = await detail({ id: "1" });
console.dir(result, { depth: null });
}
run();
But it ended up being like this
[
{
"id": "1",
"title": "Title 1",
"parentIdeaId": null
},
[
{
"id": "2",
"title": "Title 2",
"parentIdeaId": 1
},
{
"id": "3",
"title": "Title 3",
"parentIdeaId": 2
}
]
]
Where did I mess up? Thanks
findChildren potentially returns an array of arrays due to the fact that your returning Promise.all() -> which is a array of promises and some of those promises can be arrays.
So you can use concat to merge the result into the main array e.g like this https://codesandbox.io/s/quizzical-sun-c4khx?file=/src/index.js

Modifying tree structured data in JavaScript with given condition?

I have a tree data like this:
var tree = [
{
id:"11",
text: "Parent 1",
type:"Parent",
nodeSelected:false,
nodes: [
{
text: "Child 1",
parentId: "11",
id:"21",
nodeSelected:false,
type: "Child",
nodes: [
{
id:"36",
text: "Grandchild 1",
parentId: "21",
nodeSelected:false,
nodes:[],
type: "Grandchild"
},
{
id:"38",
text: "Grandchild 2",
parentId: "21",
nodes:[],
nodeSelected:false,
type: "Grandchild"
}
]
},
{
id:"43",
text: "Child 2",
nodeSelected:false,
parentId:"11",
type: "Child",
nodes: [
{
id:"52",
parentId:"43",
text: "Grandchild 1 of child 2",
nodeSelected:false,
nodes:[],
type: "Grandchild"
}
]
}
]
},
{
id:"46",
text: "Parent 2",
nodeSelected:false,
type: "Parent",
nodes:[]
},
{
id:"48",
text: "Parent 3",
nodeSelected:false,
type: "Parent",
node: [
{
id:"70",
text: "child 3",
parentId: "48",
type: "Child",
nodeSelected:false,
nodes:[]
}
]
}
];
All of the nodeSelected are false.
I have group of Ids in form of an array.
groupedIds=["11","21","43","52","48"];
I want to do nodeSelected property true based on groupId array with some condition.
the condition is such that if a parentId is mentioned along with its children ids then nodeSelected property of parent should remain
false and child's nodeSelected should be true (and its nodes nodeSelected should also be 'true').
Or else whole parent nodes nodeSelected should be true(along with it nodes).
So the result will be like this:
var resultArray = [
{
id:"11",
text: "Parent 1",
type:"Parent",
nodeSelected:false,
nodes: [
{
text: "Child 1",
parentId: "11",
id:"21",
nodeSelected:true,
type: "Child",
nodes: [
{
id:"36",
text: "Grandchild 1",
parentId: "21",
nodeSelected:true,
type: "Grandchild"
},
{
id:"38",
text: "Grandchild 2",
parentId: "21",
nodeSelected:true,
type: "Grandchild"
}
]
},
{
id:"43",
text: "Child 2",
nodeSelected:false,
parentId:"11",
type: "Child",
nodes: [
{
id:"52",
parentId:"43",
text: "Grandchild 1 of child 2",
nodeSelected:true,
type: "Grandchild"
}
]
}
]
},
{
id:"46",
text: "Parent 2",
nodeSelected:false,
type: "Parent"
},
{
id:"48",
text: "Parent 3",
nodeSelected:true,
type: "Parent",
node: [
{
id:"70",
text: "child 3",
parentId: "48",
type: "Child",
nodeSelected:true
}
]
}
];
(My try) Although incomplete but something like this we can do
tree.forEach((Parent) => {
if (groupedIds.includes(Parent.id)) {
let isSomeChildSelected = Parent.nodes.some((loc) => groupedIds.includes(loc.id));
if (isSomeChildSelected) {
Parent.nodes.forEach((child) => {
if (groupedIds.includes(child.id)) {
let isSomeGrandChildSelected = child.nodes.some((grandchild) => groupedIds.includes(grandchild.id));
if (isSomeGrandChildSelected) {
child.nodes.forEach((grandchild) => {
if (groupedIds.includes(grandchild.id)) {
grandchild.isSelected = true;
}
})
} else {
child.isSelected = true;
child.nodes.forEach((grandchild) => {
grandchild.isSelected = true;
})
}
}
})
} else {
Parent.isSelected = true;
Parent.nodes.forEach((child) => {
child.isSelected = true;
child.nodes.forEach((grandchild) => {
grandchild.isSelected = true;
})
})
}
}
})
The above tried method solves the issue to some extent, but it is a bit complex.
Any help would be much appreciated. Thanks!
I'm not going to do it for you (not out of malice, just because I'm not 100% sure I understand the question!), but I'll hopefully give you a big point in the right direction.
When traversing trees, 90% of the time you need something called recursion. Recursion looks like this:
function walk(items){
items.forEach(items => {
if(item.hasChildrenOrSomething){
// notice the function calls itself:
walk(item.children);
}
// Do something with item
});
}
walk(tree);
There is one important thing to note here, which is that if you do some logic after calling the function inside itself, all the children of the current item will have that logic applied. So, here we go – in your case you want something like this:
const walk = (branch) => {
branch.forEach(node => {
// Check if this object even has children:
if(node.hasOwnProperty('nodes') && node.nodes.length){
walk(node.nodes);
// Do your node.nodes.every check here
}
// Now check if this is in the array
});
}
walk(tree);
If you've used recursion before, sorry, this whole post was probably just super patronising and has missed the point of your question. If you haven't, then can I just say I am a) jealous of you for getting to experience the feeling of something so elegant for the first time and b) sorry for you for having to unravel the mind boggling nature of them.
This gives me output what I want(with recursion):
var tree = [
{
id:"11",
text: "Parent 1",
type:"Parent",
nodeSelected:false,
nodes: [
{
text: "Child 1",
parentId: "11",
id:"21",
nodeSelected:false,
type: "Child",
nodes: [
{
id:"36",
text: "Grandchild 1",
parentId: "21",
nodeSelected:false,
nodes:[],
type: "Grandchild"
},
{
id:"38",
text: "Grandchild 2",
parentId: "21",
nodes:[],
nodeSelected:false,
type: "Grandchild"
}
]
},
{
id:"43",
text: "Child 2",
nodeSelected:false,
parentId:"11",
type: "Child",
nodes: [
{
id:"52",
parentId:"43",
text: "Grandchild 1 of child 2",
nodeSelected:false,
nodes:[],
type: "Grandchild"
}
]
}
]
},
{
id:"46",
text: "Parent 2",
nodeSelected:false,
type: "Parent",
nodes:[]
},
{
id:"48",
text: "Parent 3",
nodeSelected:false,
type: "Parent",
nodes: [
{
id:"70",
text: "child 3",
parentId: "48",
type: "Child",
nodeSelected:false,
nodes:[]
}
]
}
];
groupedIds=["11","21","43","52","48"];
var selectAllNode=array=> array.forEach((value)=>{ value.nodeSelected=true; value.nodes? selectAllNode(value.nodes) : [] });
var getFilteredData = array => array.forEach((ele)=>{
if(groupedIds.includes(ele.id)){
let isSomeSelected = ele.nodes.some((val)=>groupedIds.includes(val.id));
if(isSomeSelected){
getFilteredData(ele.nodes);
} else {
ele.nodeSelected=true;
selectAllNode(ele.nodes);
}
}
});
getFilteredData(tree);
console.log(tree);

Lodash Filter Array and Get Parent Index

My Api returns this in json format
[
{
"title":"Category One",
"data":[
{
"id":"5",
"code":"0001",
"name":"Item Name"
},
{
"id":"6",
"code":"0002",
"name":"Item Name 2"
}
]
},
{
"title":"Category Two",
"data":[
{
"id":"7",
"code":"0003",
"name":"Item Name 3"
},
{
"id":"8",
"code":"0004",
"name":"Item Name 4"
}
]
}
]
I want to filter above given array by id
I tried it like:
_.filter(data, ["title.data.id", "5"]);
But returns empty array, then i also tried it like:
_.filter(data, { data: [{ id: "5" }] });
But returns the full array.
Kindly guide what am i missing here.
You need to take the wanted properties and iterate the inner array as well.
var data = [{ title: "Category One", data: [{ id: "5", code: "0001", name: "Item Name" }, { id: "6", code: "0002", name: "Item Name 2" }] }, { title: "Category Two", data: [{ id: "7", code: "0003", name: "Item Name 3" }, { id: "8", code: "0004", name: "Item Name 4" }] }],
result = _.filter(data, ({ data }) => _.some(data, ({ id }) => id === "5"));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
let obj = [
{
"title": "Category One",
"data": [
{
"id": "5",
"code": "0001",
"name": "Item Name"
},
{
"id": "6",
"code": "0002",
"name": "Item Name 2"
}
]
},
{
"title": "Category Two",
"data": [
{
"id": "7",
"code": "0003",
"name": "Item Name 3"
},
{
"id": "8",
"code": "0004",
"name": "Item Name 4"
}
]
}
]
function getFilterResult(filterValue) {
let result = {}
for (let i = 0; i < obj.length; i++) {
let data = obj[i]['data']
let index = data.findIndex(da => da.id === filterValue)
if (index > -1) {
result['title'] = obj[i].title
data[index]['name']="New Item" /* added the code for updating the Name filed */
result['data'] = [data[index]]
}
}
return result
}
let finalResult = getFilterResult("7")
console.log(finalResult)
Using lodash
let data = [
{
"title": "Category One",
"data": [
{
"id": "5",
"code": "0001",
"name": "Item Name"
},
{
"id": "6",
"code": "0002",
"name": "Item Name 2"
}
]
},
{
"title": "Category Two",
"data": [
{
"id": "7",
"code": "0003",
"name": "Item Name 3"
},
{
"id": "8",
"code": "0004",
"name": "Item Name 4"
}
]
}
];
var output = _.find(data, item => _.find(item.data, d => d.id === '7'));
output['data'][_.findIndex(output['data'], { id: '7' })]['name']= "New Item";
console.log(output)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
Here is solution with just simple JS
const data = [
{
"title":"Category One",
"data":[
{
"id":"5",
"code":"0001",
"name":"Item Name"
},
{
"id":"6",
"code":"0002",
"name":"Item Name 2"
}
]
},
{
"title":"Category Two",
"data":[
{
"id":"7",
"code":"0003",
"name":"Item Name 3"
},
{
"id":"8",
"code":"0004",
"name":"Item Name 4"
}
]
}
];
const requried = data.find(item => item.data.find(d => d.id === '5'));
console.log(requried);
Using lodash
const data = [
{
"title":"Category One",
"data":[
{
"id":"5",
"code":"0001",
"name":"Item Name"
},
{
"id":"6",
"code":"0002",
"name":"Item Name 2"
}
]
},
{
"title":"Category Two",
"data":[
{
"id":"7",
"code":"0003",
"name":"Item Name 3"
},
{
"id":"8",
"code":"0004",
"name":"Item Name 4"
}
]
}
];
const required = _.find(data, item => _.find(item.data, d => d.id === '5'));
console.log(required);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
You can do this with reduce and filter
const data = [
{
title: 'Category One',
data: [
{
id: '5',
code: '0001',
name: 'Item Name',
},
{
id: '6',
code: '0002',
name: 'Item Name 2',
},
],
},
{
title: 'Category Two',
data: [
{
id: '7',
code: '0003',
name: 'Item Name 3',
},
{
id: '8',
code: '0004',
name: 'Item Name 4',
},
],
},
];
data.reduce((acc, curr) => {
const val = curr.data.filter((d) => d.id == '5');
if (val.length) acc = [...acc, ...val];
return acc;
}, []);

convert nested object into recursive array or nested array in javascript es6

I worked nested object which I want to convert into recursive array or nested array.
I tried iterate the object something like below but it was creating single object of array.
Can anyone give suggestions or share your ideas it will helpful for me
iterate(obj) {
for (let property in obj) {
this.configArray.push({key: property,children: [], isValue: false, value: ''});
if (obj.hasOwnProperty(property)) {
const index = Object.keys(obj).indexOf(property);
if (typeof obj[property] == "object") {
this.iterate(obj[property]);
}
else {
this.configArray[index].children.push({ key: property, value: obj[property], isValue: true, children: [] });
}
}
}
}
INPUT
{
"Parent 1": {
"11": "Child 1",
"12": "Child 2",
},
"Parent 2": {
"20": {
"21": "Grand Child 1",
"22": "Grand Child 2",
}
},
"Parent 3": {
"31": "Child 1",
"32": "Child 2",
}
}
OUTPUT
[
{
key: "Parent 1",
value: "",
children: [
{ key: 11, value: "Child 1", children: [] },
{ key: 12, value: "Child 2", children: [] }
]
},
{
key: "Parent 2",
value: "",
children: [
{
key: 20,
value: "",
children: [
{ key: 21, value: "Grand Child 1", children: [] },
{ key: 22, value: "Grand Child 2", children: [] }
]
}
]
},
{
key: "Parent 3",
value: "",
children: [
{ key: 31, value: "Child 1", children: [] },
{ key: 32, value: "Child 2", children: [] }
]
},
];
You could take a recursive approach and map the value or the children, if value is an object.
function transform(object) {
return Object
.entries(object)
.map(([key, value]) => Object.assign({ key }, value && typeof value === 'object'
? { value: '', children: transform(value) }
: { value, children: [] }
));
}
var data = { "Parent 1": { 11: "Child 1", 12: "Child 2" }, "Parent 2": { 20: { 21: "Grand Child 1", 22: "Grand Child 2" } }, "Parent 3": { 31: "Child 1", 32: "Child 2" } },
result = transform(data);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Categories