Flatten data from an object with an array of objects - javascript

In my Vue project, I'm doing an API call to my Laravel (nova) backend, the data is returned as follows.
As you can see the data is an array, which contains an array of objects. Each array represents a record, while each object represents a field in that record.
There is the possibility that a record has unnecessary data.
const data = [
[
{
attribute: 'id',
value: 1,
extra: "not needed data"
},
{
attribute: 'title',
value: 'The Title',
extra: "not needed data"
},
],
[
{
attribute: 'id',
value: 2
},
{
attribute: 'title',
value: 'The Other Title'
},
],
]
I'm wondering how I can use Javascript to flatten this out so it becomes
const data = [
{id: 1, title: 'The Title'},
{id: 2, title: 'The Other Title'}
]
What I've tried
I've tried using a combination of map and filter, but the results don't even come close.

You could use map with reduce, to build an object using only the attribute and value, ignoring all other properties:
const data = [
[
{
attribute: 'id',
value: 1,
extra: "not needed data"
},
{
attribute: 'title',
value: 'The Title',
extra: "not needed data"
},
],
[
{
attribute: 'id',
value: 2
},
{
attribute: 'title',
value: 'The Other Title'
},
],
]
console.log(data.map(a => a.reduce((a, o) => (a[o.attribute] = o.value, a), {})))

Related

Angular search a key in an object and change the value of another key

I have this data below.
I need to be able to search in the objet for the id or name key and then change the 'show' key to a different value.
How example:
Search the data for id value 2 and change the show value to false.
data = [
{
id: 1,
name: 'one',
show: false;
title: 'title1',
data: [
{
id: 1,
description: 'some description'
},
{
id: 2,
description: 'some other description'
}
]
},
{
id: 2,
name: 'two',
show: true;
title: 'title2',
data: [
{
id: 1,
description: 'some description'
},
{
id: 2,
description: 'some other description'
}
]
}
]
How can I do this?
You can use the findIndex method, and then access your array using the found Index and change any property you want, here's some code that match your use case
let index = data.findIndex((x) => x.id == THE_ID_YOU_ARE_LOOKING_FOR);
if(index > -1) {
data[index].show = THE_VALUE_YOU_WANT;
}
You can also use normal array find method.
let item = data.find(x=>x.id===REQUIRED_ID);
if(item) item.show = false

I'm trying to filter items from array by accessing a nested property & checking if it property value contains a certain string

I'm trying to filter an array of objects by the summary nested property, if it includes the word Save in the summary prop value string. This is the array:
const issues = [{
id: '1',
key: 'CLS-1',
fields: {
summary: 'Save princess',
assignee: 'Mario',
}
},
{
id: '2',
key: 'CLS-2',
fields: {
summary: 'Save Mario',
assignee: 'Luigi',
}
},
{
id: '3',
key: 'CLS-3',
fields: {
summary: 'Kidnap princess',
assignee: 'Bowser',
}
},
{
id: '4',
key: 'CLS-3',
fields: {
summary: 'Get kidnap!',
assignee: 'Peach',
}
},
]
I have tried this one-liner:
const getItemsBySummary = items.filter(item => item.fields.includes('Save'));
But I get the error item.fields.includes is not a function. I'm guessing because fieldsis anobjectinstead of anarrayso it cannot run the methodincludes()`. However, I tried like so
const getItemsBySummary = items.filter(item => [item.fields].includes('Save'));
But I get an empty array. What am I doing wrong?
well since fields is an object , and you want to filtre according to the proptery summary , you should use this instead :/
const getItemsBySummary = items.filter(item => item.fields.summary.includes('Save'));
You need item.fields.summary to access the required field.
const items = [{
id: '1',
key: 'CLS-1',
fields: {
summary: 'Save princess',
assignee: 'Mario',
}
},
{
id: '2',
key: 'CLS-2',
fields: {
summary: 'Save Mario',
assignee: 'Luigi',
}
},
{
id: '3',
key: 'CLS-3',
fields: {
summary: 'Kidnap princess',
assignee: 'Bowser',
}
},
{
id: '4',
key: 'CLS-3',
fields: {
summary: 'Get kidnap!',
assignee: 'Peach',
}
},
]
const res = items.filter(item => item.fields.summary.includes('Save'));
console.log(res);

Flatten a deeply nested array with objects and arrays

I have an array of objects that contain another array with objects. The nesting is four levels deep.
The structure of the array is:
[
{
title: 'Title',
type: 'section',
links: [
{
label: 'Label',
id: 'id_1',
links: [
{
title: 'Title',
type: 'section',
links: [
{
label: 'Label',
id: 'id_2',
links: [
{
label: 'Label',
id: 'id_3',
links: [],
}
]
}
]
},
{
title: 'Other title',
type: 'section',
links: [
{
label: 'Label',
id: 'id_4',
links: [],
}
]
}
]
}
]
}
]
I want to have a flattened array with the id's of the link arrays that contain links (they are parents of submenu's).
So the desired outcome is like:
["id_1", "id_2"]
I have tried to get the outcome with this function taken from MDN:
flatDeep(arr, d = 1) {
return d > 0
? arr.reduce((acc, val) =>
acc.concat(Array.isArray(val.links)
? this.flatDeep(val.links, d - 1)
: val.links), [])
: arr.slice();
}
This gives me an empty array.
Use Array.flatMap(). Destructure each object and use an empty array as default for missing id values. Concat the id and the result of flattening the links recursively.
const flattenIds = arr => arr.flatMap(({ id = [], links }) =>
[].concat(id, flattenIds(links))
);
const data = [{ title: 'Title', type: 'section', links: [{ label: 'Label', id: 'id_1', links: [{ title: 'Title', type: 'section', links: [{ label: 'Label', id: 'id_2', links: [{ label: 'Label', id: 'id_3', links: [] }] }] }, { title: 'Other title', type: 'section', links: [{ label: 'Label', id: 'id_4', links: [] }] }] }] }];
const result = flattenIds(data);
console.log(result);
You could get a flat array with a recursion and a check for id for missing property.
const
getId = ({ id, links }) => [
...(id === undefined ? [] : [id]),
...links.flatMap(getId)
],
data = [{ title: 'Title', type: 'section', links: [{ label: 'Label', id: 'id_1', links: [{ title: 'Title', type: 'section', links: [{ label: 'Label', id: 'id_2', links: [{ label: 'Label', id: 'id_3', links: [] }] }] }, { title: 'Other title', type: 'section', links: [{ label: 'Label', id: 'id_4', links: [] }] }] }] }],
result = data.flatMap(getId);
console.log(result);
Here is a non-recursive version.
const data = [{title:'Title',type:'section',links:[{label:'Label',id:'id_1',links:[{title:'Title',type:'section',links:[{label:'Label',id:'id_2',links:[{label:'Label',id:'id_3',links:[]}]}]},{title:'Other title',type:'section',links:[{label:'Label',id:'id_4',links:[]}]}]}]}];
const stack = data.slice();
const result = [];
let obj;
while (obj = stack.shift()) {
if ("id" in obj && obj.links.length > 0) result.push(obj.id);
stack.push(...obj.links);
}
console.log(result);
This uses breath first, but can easily be changed into depth first. You'll only have to change the stack.push call into stack.unshift.
For a more detailed explanation about the two, check out Breadth First Vs Depth First.
var array = JSON.parse('[{"title":"Title","type":"section","links":[{"label":"Label","id":"id_1","links":[{"title":"Title","type":"section","links":[{"label":"Label","id":"id_2","links":[{"label":"Label","id":"id_3","links":[]}]}]},{"title":"Other title","type":"section","links":[{"label":"Label","id":"id_4","links":[]}]}]}]}]');
arr = [];
while(array.length != 0) {
var ob1 = array.splice(0,1)[0];
for(var ob2 of ob1.links) {
if (ob2.links.length !== 0) {
arr.push(ob2.id);
array = array.concat(ob2.links);
}
}
}
console.log(arr);
Here's the output as you requested:
[
"id_1",
"id_2"
]
I think recursive function will simplify. (recursively look for lists array and push the id into res).
const data = [
{
title: "Title",
type: "section",
links: [
{
label: "Label",
id: "id_1",
links: [
{
title: "Title",
type: "section",
links: [
{
label: "Label",
id: "id_2",
links: [
{
label: "Label",
id: "id_3",
links: []
}
]
}
]
},
{
title: "Other title",
type: "section",
links: [
{
label: "Label",
id: "id_4",
links: []
}
]
}
]
}
]
}
];
const res = [];
const ids = data => {
data.forEach(item => {
if ("id" in item) {
res.push(item.id);
}
if (item.links) {
ids(item.links);
}
});
};
ids(data);
console.log(res);

Assign array values to an item in object - Javascript/React

I have an object with few items and I want to update the values of one property from array.
Object :
structure = [
{
id: 'name',
label: 'Name',
filterType: 'text',
filterOn: 'contains'
},
{
id: 'address',
label: 'Address',
filterType: 'text',
filterOn: 'contains'
},
{
id: 'phone',
label: 'Phone',
filterType: 'select',
filterOn: 'contains',
options: [{ label: 'abc', value: 'abc' },
{ label: 'xyz', value: 'xyz' },
{ label: 'mno', value: 'mno' }]
}
];
if the id is phone then I want to get the values from the array and assign it to the options instead of hard coding it.
In this object of id phone:
options: [{ label: 'abc', value: 'abc' },
{ label: 'xyz', value: 'xyz' },
{ label: 'mno', value: 'mno' }]
}
];
array is coming from
this.props.phoneList
label and values will be this.props.phoneList[i].name
how to loop over this and get the latest values from the array
This should keep the order of the array intact also:
const newStructure = structure.map(item => {
const isPhone = item.id === “phone”
return {
...item,
options: isPhone ? this.props.phoneList : (item.options || undefined)
}
}

Javascript array with a mix of literals and arrays

How can I create an json format in javascript
var data = [
{
label: 'node1',
children: [
{ label: 'child1' },
{ label: 'child2' }
]
},
{
label: 'node2',
children: [
{ label: 'child3' }
]
}
]
I can add the 'node' using data.push, but how to proceed with childrens?
Thank's!
First off, there is no such thing as a JSON array. You are working with an array. JSON is a way to transfer data between systems.
You have an array called data that you need to push an object into...
so something like:
data.push({
label: 'node3',
children: [
{ label: 'child3' },
{ label: 'child3' }
]
});
Now.. you've got a problem at this point, because you are duplicating the label property, which is not allowed under ES5 strict mode.

Categories

Resources