create nested json from plain jsons - javascript

I need to create a nested json object from a node-mysql results (json objects) here is what I'm trying to acomplish
Those are the mysql json objects that I have:
plants:
[{id: 1, name: 'plant 1'},
{id: 2, name: 'plant 2'}]
areas:
[{id: 1, nombre: 'area 1', plants_id: 1 },
{ id: 2, nombre: 'area 1 - plant 2', plantas_id: 2 },
{ id: 3, nombre: 'area n', plantas_id: 1 }]
machines:
[{id: 1, nombre: 'machine 1 - area 1', areas_id: 1 },
{ id: 2, nombre: 'machine 1 - area 2', areas_id: 2 },
{ id: 3, nombre: 'machine n', areas_id: 2 }]
And this the json that I need to create with the values of the previous json:
{
"plants":[
{
"name":"plant 1",
"areas": [
{ "name":"area 1",
"machines":[
{"nombre":"machine 1 - area 1"
}]
},
{ "nombre":"area 2",
"machines":[
{"nombre":"machine 1 - area 2"
}]
}
]
},
{
"name":"plant 2",
"areas": [
{ "nombre":"area 1 - plant 2",
"maquinas":[ ]
}
]
}
]
}
I've been trying with nested for loops but it's a mess, I read about linq but I have never worked with it
Sorry for the bad english. Any help is appreciated
Thanks and regards

This isn't an efficient solution but if your dataset is small, it works.
var plants = [
{ id: 1, name: 'plant 1' },
{ id: 2, name: 'plant 2' },
];
var areas = [
{ id: 1, nombre: 'area 1', plantas_id: 1 }, // there was a spelling mistake here
{ id: 2, nombre: 'area 1 - plant 2', plantas_id: 2 },
{ id: 3, nombre: 'area n', plantas_id: 1 },
];
var machines = [
{ id: 1, nombre: 'machine 1 - area 1', areas_id: 1 },
{ id: 2, nombre: 'machine 1 - area 2', areas_id: 2 },
{ id: 3, nombre: 'machine n', areas_id: 2 },
];
console.time('result');
function result() {
return plants.map(function(plant) {
return {
"name": plant.name,
"areas": areas.filter(function(area) {
return area.plantas_id == plant.id;
}).map(function(area) {
return {
"nombre": area.nombre,
"machines": machines.filter(function(machine) {
return machine.areas_id == area.id;
}).map(function(machine) {
return {
"nombre": machine.nombre,
};
}),
};
}),
};
});
}
console.timeEnd('result');
console.log(result());

Related

Access nested array of objects

im having real trouble to complete an FullStackOpen exersice, it requires to render some data to the page. Give the next code, i have to render the number of Parts that each Course has, and also so reduce the number of Parts/Exersices to render the total of exersices por each Course.
I am not being able to reach the inside of the Parts array of objects
{
name: "Half Stack application development",
id: 1,
parts: [
{
name: "Fundamentals of React",
exercises: 10,
id: 1,
},
{
name: "Using props to pass data",
exercises: 7,
id: 2,
},
{
name: "State of a component",
exercises: 14,
id: 3,
},
{
name: "Redux",
exercises: 11,
id: 4,
},
],
},
{
name: "Node.js",
id: 2,
parts: [
{
name: "Routing",
exercises: 3,
id: 1,
},
{
name: "Middlewares",
exercises: 7,
id: 2,
},
],
},
];```
It's not that difficult, for each element of the array:
number of parts is currentElement.parts.length
number of exercises can be computed using Array.reduce
const data = [
{
name: "Half Stack application development",
id: 1,
parts: [{
name: "Fundamentals of React",
exercises: 10,
id: 1,
},
{
name: "Using props to pass data",
exercises: 7,
id: 2,
},
{
name: "State of a component",
exercises: 14,
id: 3,
},
{
name: "Redux",
exercises: 11,
id: 4,
},
],
},
{
name: "Node.js",
id: 2,
parts: [{
name: "Routing",
exercises: 3,
id: 1,
},
{
name: "Middlewares",
exercises: 7,
id: 2,
},
],
},
];
const res = []
for (const course of data) {
const tmpObj = {
courseName: course.name,
parts: course.parts.length,
exercises: course.parts.reduce((a,b) => a + b.exercises, 0)
}
res.push(tmpObj)
}
console.log(res)
If you want a total number of exercises per course, you will need to reduce each by name; and for each list of parts, reduce by the exercise count.
const main = () => {
const courseData = courses.map(({ name, parts }) => ({
name,
parts: parts.length,
exercises: parts.reduce((sum, { exercises }) => sum + exercises, 0)
}));
console.log(courseData);
};
const courses = [{
name: "Half Stack application development",
id: 1,
parts: [
{ name: "Fundamentals of React" , exercises: 10 , id: 1 },
{ name: "Using props to pass data" , exercises: 7 , id: 2 },
{ name: "State of a component" , exercises: 14 , id: 3 },
{ name: "Redux" , exercises: 11 , id: 4 }
],
}, {
name: "Node.js",
id: 2,
parts: [
{ name: "Routing" , exercises: 3 , id: 1 },
{ name: "Middlewares" , exercises: 7 , id: 2 }
],
}];
main();
.as-console-wrapper { top: 0; max-height: 100% !important; }

How to flatten an object that has array of objects in Javascript

I am trying to solve this question it needs me to flatten this object parent that it has children each parent has 2 children, and each child has 2 children and so on....
My goal is to flatten this to one single object.
const par = {
id: 1,
name: "parent",
children: [{
id: 2,
name: "child 1",
children:[{
id: 4,
name: "child 3",
children: [],
},{
id: 5,
name: "child 4 ",
}]
},{
id: 3,
name: "child 2",
children: [{
id: 6,
name: "child 5",
},{
id: 7,
name: "child 6",
children: []
}]
}]
}
I tried function, but it returns an array from
Deep Flatten JavaScript Object Recursively
function flat(r, a) {
let b = {};
Object.keys(a).forEach(function (k) {
if (k !== 'children') {
b[k] = a[k];
}
});
r.push(b);
if (Array.isArray(a.children)) {
b.children = a.children.map(function (a) { return a.id;});
return a.children.reduce(flat, r);
}
return r;
}
You still owe us a description of your desired output. But if you want something as simple as this:
[
{id: 1, name: "parent"},
{id: 2, name: "child 1"},
{id: 4, name: "child 3"},
{id: 5, name: "child 4"},
{id: 3, name: "child 2"},
{id: 6, name: "child 5"},
{id: 7, name: "child 6"}
]
Then a depth-first recursive function can be as simple as this:
const flatten = ({children = [], ...rest}) => [rest, ...children .flatMap (flatten)]
const par = {id: 1, name: "parent", children: [{id: 2, name: "child 1", children: [{id: 4, name: "child 3", children: []}, {id: 5, name: "child 4 ", }]}, {id: 3, name: "child 2", children: [{id: 6, name: "child 5", }, {id: 7, name: "child 6", children: []}]}]}
console .log (flatten (par))
.as-console-wrapper {max-height: 100% !important; top: 0}
If you wanted to include a parentId field, using null for root-level objects, it's only slightly more complex:
const flatten = ({id, children = [], ...rest}, parentId = null) => [
{id, ...rest, parentId}, ...children .flatMap (c => flatten(c, id))
]
Here's an effective technique using a recursive generator flat -
function *flat({ children = [], ...t }, parentId = null) {
yield { ...t, parentId }
for (const child of children)
yield *flat(child, t.id)
}
const par = {id: 1,name: "parent",children: [{id: 2,name: "child 1",children:[{id: 4,name: "child 3",children: [],},{id: 5,name: "child 4 ",}]},{id: 3,name: "child 2",children: [{id: 6,name: "child 5",},{id: 7,name: "child 6",children: []}]}]}
console.log(Array.from(flat(par)))
.as-console-wrapper { min-height: 100%; top: 0; }
You can collect all the results of a generator using Array.from -
[
{
"id": 1,
"name": "parent",
"parentId": null
},
{
"id": 2,
"name": "child 1",
"parentId": 1
},
{
"id": 4,
"name": "child 3",
"parentId": 2
},
{
"id": 5,
"name": "child 4 ",
"parentId": 2
},
{
"id": 3,
"name": "child 2",
"parentId": 1
},
{
"id": 6,
"name": "child 5",
"parentId": 3
},
{
"id": 7,
"name": "child 6",
"parentId": 3
}
]
Or you can simply iterate thru the generator's result directly -
for (const flatNode of flat(par)) {
// do something with flatNode ...
}
See this related Q&A for a technique to convert the flat tree back to a recursive tree or graph.
You can try this
function flatTree(tree, parentId = null) {
const { id, name, children } = tree;
const result = [{ id, name, parentId }];
if (Array.isArray(children)) {
children.forEach((child) => {
result.push(...flatTree(child, id));
});
}
return result;
}
const par = {
id: 1,
name: "parent",
children: [
{
id: 2,
name: "child 1",
children: [
{
id: 4,
name: "child 3",
children: [],
},
{
id: 5,
name: "child 4 ",
},
],
},
{
id: 3,
name: "child 2",
children: [
{
id: 6,
name: "child 5",
},
{
id: 7,
name: "child 6",
children: [],
},
],
},
],
};
console.log(flatTree(par));
/**
* Output:
* [
{ id: 1, name: 'parent', parentId: null },
{ id: 2, name: 'child 1', parentId: 1 },
{ id: 4, name: 'child 3', parentId: 2 },
{ id: 5, name: 'child 4 ', parentId: 2 },
{ id: 3, name: 'child 2', parentId: 1 },
{ id: 6, name: 'child 5', parentId: 3 },
{ id: 7, name: 'child 6', parentId: 3 }
]
*/
Here is a solution using object-scan. Reinventing the wheel is typically not as bug-free, flexible or maintainable as using a battle-tested library!
.as-console-wrapper {max-height: 100% !important; top: 0}
<script type="module">
import objectScan from 'https://cdn.jsdelivr.net/npm/object-scan#18.4.0/lib/index.min.js';
const par = { id: 1, name: 'parent', children: [{ id: 2, name: 'child 1', children: [{ id: 4, name: 'child 3', children: [] }, { id: 5, name: 'child 4 ' }] }, { id: 3, name: 'child 2', children: [{ id: 6, name: 'child 5' }, { id: 7, name: 'child 6', children: [] }] }] };
const fn = objectScan(['**{children[*]}.id'], {
rtn: ({ parent: { id, name } }) => ({ id, name })
});
const r = fn(par);
console.log(r);
/* => [
{ id: 7, name: 'child 6' },
{ id: 6, name: 'child 5' },
{ id: 3, name: 'child 2' },
{ id: 5, name: 'child 4 ' },
{ id: 4, name: 'child 3' },
{ id: 2, name: 'child 1' },
{ id: 1, name: 'parent' }
] */
</script>
Disclaimer: I'm the author of object-scan

How to group an array of objects and mapping it to a different structure?

It's actually about mapping an array of objects and grouping it. Is there any way to convert this array the javascript way without lodash
let fruits = [
{
id: 1,
expired_date: "2021-11-30",
name: "mango"
},
{
id: 2,
expired_date: "2021-11-20",
name: "kiwi"
},
{
id: 3,
expired_date: "2021-11-20",
name: "orange"
},
{
id: 4,
expired_date: "2021-11-10",
name: "banana"
},
{
id: 5,
expired_date: "2021-11-10",
name: "apple"
}
]
grouped to something like this? (grouped by a key in the object, wrapped in an object with 2 keys, one contains the category and the other contains the objects relevant to the group)
let fruits = [
{
expired_date: "2021-11-30",
rows: [
{
id: 1,
expired_date: "2021-11-30",
name: "mango"
}
]
},
{
expired_date: "2021-11-20",
rows: [
{
id: 2,
expired_date: "2021-11-20",
name: "kiwi"
},
{
id: 3,
expired_date: "2021-11-20",
name: "orange"
}
]
},
{
expired_date: "2021-11-10",
rows: [
{
id: 4,
expired_date: "2021-11-10",
name: "banana"
},
{
id: 5,
expired_date: "2021-11-10",
name: "apple"
}
]
}
]
I've read this question but it's not quite the same as expected
Array.reduce should work
const fruits = [ { id: 1, expired_date: "2021-11-30", name: "mango" }, { id: 2, expired_date: "2021-11-20", name: "kiwi" }, { id: 3, expired_date: "2021-11-20", name: "orange" }, { id: 4, expired_date: "2021-11-10", name: "banana" }, { id: 5, expired_date: "2021-11-10", name: "apple" }];
const result = Object.values(fruits.reduce((acc, item) => {
(acc[item.expired_date]??={expired_date: item.expired_date, rows: []}).rows.push(item);
return acc;
}, {}));
console.log(result);
Revised without ??= assignment, it's not supported in IE.
const result = Object.values(fruits.reduce((acc, item) => {
if (acc[item.expired_date]) {
acc[item.expired_date].rows.push(item);
} else {
acc[item.expired_date] = {expired_date: item.expired_date, rows: [item]};
}
return acc;
}, {}));

Filter object from array based on multiple nested values

Basically I'm trying to figure out the cleanest way to select one item from an array, only if all certain values exist.
const filterValues = ['blue', '30cm', 'true'];
const products = [
{
details: [
{ id: 1, value: 'red' },
{ id: 2, value: '30cm' },
{ id: 3, value: 'true' },
{ id: 4, value: '123432'}
],
name: "Product 1"
},
{
details: [
{ id: 5, value: 'blue' },
{ id: 6, value: '30cm' },
{ id: 7, value: 'true' },
{ id: 8, value: '98348'}
],
name: "Product 2"
},
{
details: [
{ id: 9, value: 'black' },
{ id: 10, value: '40cm' },
{ id: 11, value: 'false' },
{ id: 12, value: '578347'}
],
name: "Product 3"
},
]
Only Product 2 contains all the filter values, so I want to return that product.
I have tried:
products.filter(p => {
p.details.find(k => filterValues.includes(k.value));
})
but this returns if any of the values satisfies the condition rather than if all of them are included. This is the main issue here. I'm struggling with finding a way to filter if only all these values int he array are present in the object.
Use Array#every.
const filterValues = ['blue', '30cm', 'true'];
const products = [
{
details: [
{ id: 1, value: 'red' },
{ id: 2, value: '30cm' },
{ id: 3, value: 'true' },
{ id: 4, value: '123432'}
],
name: "Product 1"
},
{
details: [
{ id: 5, value: 'blue' },
{ id: 6, value: '30cm' },
{ id: 7, value: 'true' },
{ id: 8, value: '98348'}
],
name: "Product 2"
},
{
details: [
{ id: 9, value: 'black' },
{ id: 10, value: '40cm' },
{ id: 11, value: 'false' },
{ id: 12, value: '578347'}
],
name: "Product 3"
},
]
console.log(products.filter(p => filterValues.every(fv => p.details.map(d => d.value).includes(fv))));

Assign new properties to an array of Objects

I have an array of Objects
const options = [
{ id: 1, name: "Back Pain" },
{ id: 2, name: "Body aches" },
{ id: 3, name: "Cold Sores" },
{ id: 4, name: "Cough" },
{ id: 5, name: "Constipation" },
];
I am trying to write a function that will assign new properties to the object.
The output I am looking for is:
const options = [
{ value: 1, label: "Back Pain" },
{ value: 2, label: "Body aches" },
{ value: 3, label: "Cold Sores" },
{ value: 4, label: "Cough" },
{ value: 5, label: "Constipation" },
];
I have tried to loop through the array using a for loop, but can not figure it out.
Thanks for the help:)
You can do it like this:
const data=[{ id: 1, name: "Back Pain" },
{ id: 2, name: "Body aches" },
{ id: 3, name: "Cold Sores" },
{ id: 4, name: "Cough" },
{ id: 5, name: "Constipation" },
];
var result = data.map(({id:value, name:label})=>({value, label}));
console.log(result);

Categories