how to turn an object of arrays into array of objects? - javascript

the structure of the data axios gets is:
{
"data": {
"project": {
"id": "5ebd525ea3ff2434c0d467f8",
"items": [
{
"name": "item one",
"size": 45,
"createdAt": "2020-05-14T14:15:43.034Z",
},
{
"name": "item two",
"size": 23,
"createdAt": "2020-05-14T14:15:58.508Z",
},
{
"name": "item one",
"size": 93,
"createdAt": "2020-05-14T15:02:19.889Z"
},
{
"name": "item two",
"size": 55,
"createdAt": "2020-05-19T02:48:14.486Z"
}
]
}
}
}
I need to accomplish is two things:
Group the items by name
map to new arrays to render in a chart
the code i have is
async created() {
const response = await axios.get(
`http://localhost:1337/projects/${this.routeId}`
))
const { items } = response.data
//returns new array of only fields needed to send to the chart
const newArray = items.map(({name, size, createdAt}) => ({name, size, createdAt}))
// group items by name **** this creates an object of arrays
const groupBy = (array, key) => {
return array.reduce((result, currentValue) => {
(result[currentValue[key]] = result[currentValue[key]] || [])
.push(currentValue);
return result
}, {})
};
const itemsGroupedByName = groupBy(newArray, 'name')
//this fails *** trying to map an object into a new array
itemsGroupByName.forEach(d => {
const { name, size, createdAt } = d
this.arrItemSize.push({
date: moment(createdAt).format('MMM D YYYY'),
total: size,
name
})
})
},
The code above groups the items as object of arrays -
{ [...], [...], [...], [...] }
The format the chart needs is array of objects
[ {...}, {...}, {...}, {...]
How do I map the grouped items to new arrays?
Thanks for any help

You can use the function Array.prototype.reduce for grouping and the function Object.values for extracting the grouped objects.
This is assuming the property items will contain the grouped objects.
let obj = { "data": { "project": { "id": "5ebd525ea3ff2434c0d467f8", "items": [ { "name": "item one", "size": 45, "createdAt": "2020-05-14T14:15:43.034Z", }, { "name": "item two", "size": 23, "createdAt": "2020-05-14T14:15:58.508Z", }, { "name": "item one", "size": 93, "createdAt": "2020-05-14T15:02:19.889Z" }, { "name": "item two", "size": 55, "createdAt": "2020-05-19T02:48:14.486Z" } ] } } };
let result = Object.values(obj.data.project.items.reduce((a, {name, ...rest}) => {
(a[name] || (a[name] = {items: []}))["items"].push({name, ...rest});
return a;
}, Object.create(null)));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

Javascript nested array to object conversion

I have an array of objects in the following format. It basically a nested array of objects. I tried to do it using a recursive function, but I failed to organize the nested object.
[
{
"id": "31a3sd2f1a3ds21f",
"name": "Energy device",
"child": [
{
"id": "65sa4d65a4sdf654adsf",
"name": "Device 2",
"child": [
{
"id": "65a4d65ad4s54adsf",
"name": "Device 3",
"child": []
}
]
}
]
},
{
"id": "6as54d54as5f",
"name": "Energy device 2",
"child": [
{
"id": "9a8s7df98a78sdf",
"name": "Device 4",
"child": [
{
"id": "65a4d65ad4s54adsf",
"name": "Device 5",
"child": []
}
]
},
{
"id": "65asd54as5f4",
"name": "Device 5-1",
"child": []
}
]
}
]
I want to convert it to the following format.
{
"31a3sd2f1a3ds21f": {
"65sa4d65a4sdf654adsf": {
"65a4d65ad4s54adsf": ""
}
},
"6as54d54as5f": {
"9a8s7df98a78sdf": {
"65a4d65ad4s54adsf": ""
},
"65asd54as5f4": ""
}
}
Is there anyone who can help me?
You can map each object within your array to new arrays of the shape [key, value]. For each object, you can extract the id and child properties using desturcutring assignment in your callback argument ({id, child}) => ...). You can then return an array for that object that represents an entry for the new object your building. The key is the id of the current object, and the value is either a new object based on the child array which you can build by doing a recursive call, or an empty string if your current object doesn't have any children. This allows you to add the nesting to the objects as you build them. Finally, you can wrap the mapped version of your arr into a call to Object.fromEntries() which allows you to convert the array of [key, value] pair entries into an object:
const arr = [ { "id": "31a3sd2f1a3ds21f", "name": "Energy device", "child": [ { "id": "65sa4d65a4sdf654adsf", "name": "Device 2", "child": [ { "id": "65a4d65ad4s54adsf", "name": "Device 3", "child": [] } ] } ] }, { "id": "6as54d54as5f", "name": "Energy device 2", "child": [ { "id": "9a8s7df98a78sdf", "name": "Device 4", "child": [ { "id": "65a4d65ad4s54adsf", "name": "Device 5", "child": [] } ] }, { "id": "65asd54as5f4", "name": "Device 5-1", "child": [] } ] } ];
const mapToId = (arr) => Object.fromEntries(arr.map(({id, child}) => [
id, child.length ? mapToId(child) : ""
]));
const res = mapToId(arr);
console.log(res);
I don't know why you wanted the final child to be an empty string instead of an empty object, but here it is:
function arrayToObject(array) {
// Create empty object if array has cildren, else create an empty string
const obj = array.length > 0 ? {} : '';
// Recursively add children to object
array.forEach((item) => {
obj[item.id] = arrayToObject(item.child);
});
return obj;
}

Convert object of objects of key value to array of object of same key value and return the after each iteration

I am trying to convert object with object inside to array of objects.
I have the data as:
"data" :{
"tDetails": {
"tName": "Limited",
"tPay": " xyz",
},
"bDetails": {
"bName": "name",
"bid": "bid",
"bNo": "123456",
},
"iDetails": {
"iName": "iname",
"iBranch": "ibranch",
},
}
i want to convert it to array of objects with each iteration over the three headers(tDetails, iDetails,bDetails) as:
const newData = [
{
"id": 1,
"title": "tDetails",
"content": [
{
"id": 1,
"key": "tName",
"value": "Limited"
},
{
"id": 2,
"key": "tPay",
"value": "xyz"
}
]
},
{
"id": 2,
"title": "bDetails",
"content": [
{
"id": 1,
"key": "bId",
"value": "12345"
}
]
},
{
"id": 3,
"title": "iDetails",
"content": [
{
"id": 1,
"key": "iName",
"value": "iname"
},{
"id":2,
"key": "iBranch",
"value": "ibranch"
}
]
},
]
const NewData = () => {
let newDetails = [];
let newHeader = '';
for (const header in data) {
// header here is 'tDetails', bDetails, iDetails
const headerData = data[header];
newDetails = Object.entries(headerData).map(([key, value]) => ({
key,
value,
}));
newHeader = header;
}
return [
{
title: newHeader,
content: newDetails,
},
];
};
This returns me the data of only the last part(iDetails) as it is returned after the for loop.What should be changed here
Map the object's entries instead of using for..in, and in the callback, return the transformed object.
const data={tDetails:{tName:"Limited",tPay:" xyz"},bDetails:{bName:"name",bid:"bid",bNo:"123456"},iDetails:{iName:"iname",iBranch:"ibranch"}};
const newData = Object.entries(data).map(([title, obj], i) => ({
title,
id: i + 1,
content: Object.entries(obj).map(([key, value], j) => ({
id: j + 1,
key,
value
}))
}));
console.log(newData);

Attempting to flatten nested objects based on a specific field key

Am looking to map through an array, take the key/value of a specified field, then merge it into the main object.
Currently my array looks like:
const data = [
{
"id": "3QXNO4SDo08FgAfQy3z5",
"title": "Team One",
"scores": [
{
"id": "DbkZljn22YSGVBLxiT4o",
"score": 88
},
{
"id": "v7ss2ypT4qf9RIvIynJp"
"score": 5,
}
]
},
{
"id": "EmoL3dlPWpOPPiLixIYJ",
"title": "Team Two",
"scores": [
{
"id": "DbkZljn22YSGVBLxiT4o",
"score": 77,
},
{
"id": "v7ss2ypT4qf9RIvIynJp",
"score": 0,
}
]
}
]
And I need to simplify it down to:
[
{
"id": "3QXNO4SDo08FgAfQy3z5",
"title": "Team One",
"DbkZljn22YSGVBLxiT4o": 88,
"v7ss2ypT4qf9RIvIynJp": 5,
},
{
"id": "EmoL3dlPWpOPPiLixIYJ",
"title": "Team Two",
"DbkZljn22YSGVBLxiT4o": 77,
"v7ss2ypT4qf9RIvIynJp": 0,
}
]
Taking the unique ID of the score and using it as my object key.
I imagine this requires nested looping to get the result. I would post my coding attempts, but they were seriously flawed and confusing.
You can combine Array#map and Array#reduce to achieve the desired output.
const mapped = data.map(({ scores, ...rest }) => ({
...rest,
...scores.reduce((output, score) => ({ ...output, [score.id]: score.score }), {})
}));
your questiopn is not clear ..
but this answer may help you
const data= [
{
"id": "3QXNO4SDo08FgAfQy3z5",
"title": "Team One",
"scores": [
{
"id": "DbkZljn22YSGVBLxiT4o",
"score": 88
},
{
"id": "v7ss2ypT4qf9RIvIynJp"
"score": 5,
}
]
},
{
"id": "EmoL3dlPWpOPPiLixIYJ",
"title": "Team Two",
"scores": [
{
"id": "DbkZljn22YSGVBLxiT4o",
"score": 77,
},
{
"id": "v7ss2ypT4qf9RIvIynJp",
"score": 0,
}
]
}
]
by click on data field:
const array = [];
function handleSelect(id) {
const copyData = [...data];
const foundItems = copyData.map(item => item.id === id);
array.push(foundItems)
}
finally array is:
const array = [
{
"id": "3QXNO4SDo08FgAfQy3z5",
"title": "Team One",
"DbkZljn22YSGVBLxiT4o": 88,
"v7ss2ypT4qf9RIvIynJp": 5,
},
{
"id": "EmoL3dlPWpOPPiLixIYJ",
"title": "Team Two",
"DbkZljn22YSGVBLxiT4o": 77,
"v7ss2ypT4qf9RIvIynJp": 0,
}
]
const flattenedArray = data.map((dt) => {
let ar = [];
dt.scores.forEach((n, i) => (ar = { ...ar, [n.id]: n.score }));
return { ...dt, ...ar };
});
Returns the desired flattened array.

Returning parent key based on a value in a list of arrays in Javascript

{
"arr1":[
{
"name":"something1",
"id":"233111f4-9126-490d-a78b-1724009fa484"
},
{
"name":"something2",
"id":"50584c03-ac71-4225-9c6a-d12bcc542951"
},
{
"name":"Unique",
"id":"43cf14ee58ea4d8da43e9a2f208d215c"
},
{
"name":"something4",
"id":"ce0374ba-6d9b-4ff5-98b1-1191d1d2a9a7"
},
{
"name":"something5",
"id":"ef825dc3-003c-4740-955a-bb437cfb4199"
}
],
"arr2":
[
{
"name":"Unique",
"id":"43cf14ee58ea4d8da43e9a2f208d215c"}
]
}
This is list of arrays with keys and values as array, I want to return all the keys based on a particular value;
For Eg:
I want to return the parent keys which are [arr1,arr2], reason being both the arrays contain a value Unique, So I want to return the parent key of both the values, which is arr1 and arr2 respectively.
Note: The list can have n numbers of arrays.
Any help would be appreciated. Thanks in advance.
The simplest way to go about this is:
Loop through the keys in your object
Check if the array contains any objects with the name "Unique"
If so, add the objects key to an array
const obj = {
"arr1": [{ "name": "something1", "id": "233111f4-9126-490d-a78b-1724009fa484" }, { "name": "something2", "id": "50584c03-ac71-4225-9c6a-d12bcc542951" }, { "name": "Unique", "id": "43cf14ee58ea4d8da43e9a2f208d215c" }, { "name": "something4", "id": "ce0374ba-6d9b-4ff5-98b1-1191d1d2a9a7" }, { "name": "something5", "id": "ef825dc3-003c-4740-955a-bb437cfb4199" }],
"arr2": [{ "name": "Unique", "id": "43cf14ee58ea4d8da43e9a2f208d215c" }],
"arr3": [{ "name": "No unique here","id": "Example" }]
}
// Create our array that will contain the keys
const keys = []
// Loop through each key in the object
for (const prop in obj) {
// Use .some to see if any of the objects in this array have the selected name
const containsUnique = obj[prop].some(o => o.name === 'Unique')
if (containsUnique) {
// Add the current key to the array
keys.push(prop)
}
}
// Use the array of keys which contain an object named "Unique"
console.log(keys)
This is a more generic approach:
const getKeysByValue = (data, value) => {
const dataKeys = Object.keys(data);
const valueKey = Object.keys(value);
return dataKeys.filter(currKey => {
for(let element of data[currKey])
if(element[valueKey] === value[valueKey])
return true;
});
}
const data = {
"arr1":[
{
"name":"something1",
"shape": "Trapezium",
"id":"233111f4-9126-490d-a78b-1724009fa484"
},
{
"name":"something2",
"shape": "Octagon",
"id":"50584c03-ac71-4225-9c6a-d12bcc542951"
},
{
"name":"Unique",
"shape": "Square",
"id":"43cf14ee58ea4d8da43e9a2f208d215c"
},
{
"name":"something4",
"shape": "Triangle",
"id":"ce0374ba-6d9b-4ff5-98b1-1191d1d2a9a7"
},
{
"name":"something5",
"shape": "Circle",
"id":"ef825dc3-003c-4740-955a-bb437cfb4199"
}
],
"arr2":
[
{
"name":"Unique",
"shape": "Triangle",
"id":"43cf14ee58ea4d8da43e9a2f208d215c"
}
],
"arr3":
[
{
"name":"Not-Unique",
"shape": "Circle",
"id":"8hcf14ee58ea25g343e9a2f208df215c"
}
]
}
console.log(getKeysByValue(data, {"name": "something2"})); // ["arr1"]
console.log(getKeysByValue(data, {"name": "Unique"})); // ["arr1", "arr2"]
console.log(getKeysByValue(data, {"shape": "Circle"})); // ["arr1", "arr3"]
console.log(getKeysByValue(data, {"shape": "Square"})); // ["arr1"]
The function receives two parameters, data and value. value is expected to be in the format of the value you are looking to filter with. In your example you wanted it to be "Unique" and in each object in the array it was presented like "name": "Unique" so we will send it as an object, {"name": "Unique"}.
In this way you can have different value to filter with. In the example above I added a shape key and value to each element, we can filter by this value too as shown in the example above.
you can do like this :
const obj = {
"arr1": [{ "name": "something1", "id": "233111f4-9126-490d-a78b-1724009fa484" }, { "name": "something2", "id": "50584c03-ac71-4225-9c6a-d12bcc542951" }, { "name": "Unique", "id": "43cf14ee58ea4d8da43e9a2f208d215c" }, { "name": "something4", "id": "ce0374ba-6d9b-4ff5-98b1-1191d1d2a9a7" }, { "name": "something5", "id": "ef825dc3-003c-4740-955a-bb437cfb4199" }],
"arr2": [{ "name": "Unique", "id": "43cf14ee58ea4d8da43e9a2f208d215c" }],
"arr3": [{ "name": "No unique here","id": "Example" }]
}
arr=[]
//loop over dict with pair keys and value
for (const [key, value] of Object.entries(obj)) {
//get the list of name from dict and check it if it contains Unique string
value.map(e=>e.name).includes("Unique") ? arr.push(key) : false
}
console.log(arr)
You can use array some method
const data = {
"arr1": [{
"name": "something1",
"id": "233111f4-9126-490d-a78b-1724009fa484"
},
{
"name": "something2",
"id": "50584c03-ac71-4225-9c6a-d12bcc542951"
},
{
"name": "Unique",
"id": "43cf14ee58ea4d8da43e9a2f208d215c"
},
{
"name": "something4",
"id": "ce0374ba-6d9b-4ff5-98b1-1191d1d2a9a7"
},
{
"name": "something5",
"id": "ef825dc3-003c-4740-955a-bb437cfb4199"
}
],
"arr2": [{
"name": "Unique",
"id": "43cf14ee58ea4d8da43e9a2f208d215c"
}]
}
var obj = [],
keys;
for (keys in data) {
data[keys].some(a => "Unique" === a.name) && obj.push(keys);
}
console.log(obj);
An alternative way that i could think of is using Regexp
var obj = {
"arr1":[
{
"name":"something1",
"id":"233111f4-9126-490d-a78b-1724009fa484"
},
{
"name":"something2",
"id":"50584c03-ac71-4225-9c6a-d12bcc542951"
},
{
"name":"Unique",
"id":"43cf14ee58ea4d8da43e9a2f208d215c"
},
{
"name":"something4",
"id":"ce0374ba-6d9b-4ff5-98b1-1191d1d2a9a7"
},
{
"name":"something5",
"id":"ef825dc3-003c-4740-955a-bb437cfb4199"
}
],
"arr2":
[
{
"name":"Unique",
"id":"43cf14ee58ea4d8da43e9a2f208d215c"}
]
}
let str = JSON.stringify(obj);
let match = str.matchAll(/\"([\w\d]+)\":\[(?:{[\s\S]+},)*{\"name\":\"Unique\"/g);
let parent = [];
for(let m of match){
parent.push(m[1]);
}

How to sort object according to nested array elements

I need to sort the main data by the oldest created account.
In the example below, the first element in the list would be id = 2. That's because the id = 2 contains the oldest created account (named account3, which was created at 2020-10-05, while the other accounts have been created after that date).
I'm using nodejs. Is there an es-function that can solve this problem in an easy way?
The object data looks like this:
{
"data": [{
"id": 1,
"accounts": [{
"id": 333,
"data": {
"name": "account1",
"createdAt": "2020-10-07T09:27:28.032Z"
}
}]
}, {
"id": 2,
"accounts": [{
"id": 334,
"data": {
"name": "account2",
"createdAt": "2020-10-06T09:27:28.032Z"
}
}, {
"id": 335,
"data": {
"name": "account3",
"createdAt": "2020-10-05T09:27:28.032Z"
}
}]
}]
}
You can often solve this problem with map --> sort --> map.
It does 3 passes on the input but remains O(n log n). You could further optimize, but I doubt this becomes a bottleneck.
Map to [record, oldestAccountDate] tuples.
Sort the tuples by oldestAccountDate.
Map again to unwrap the record.
const wrapper = {
"data": [{
"id": 1,
"accounts": [{
"id": 333,
"data": {
"name": "account1",
"createdAt": "2020-10-07T09:27:28.032Z"
}
}]
}, {
"id": 2,
"accounts": [{
"id": 334,
"data": {
"name": "account2",
"createdAt": "2020-10-06T09:27:28.032Z"
}
}, {
"id": 335,
"data": {
"name": "account3",
"createdAt": "2020-10-05T09:27:28.032Z"
}
}]
}]
};
wrapper.data = wrapper.data
.map(rec => [rec, Math.min(...rec.accounts.map(acc => new Date(acc.data.createdAt)))])
.sort((a, b) => a[1] - b[1])
.map(tuple => tuple[0]);
console.log(wrapper);
const data = [{
"id": 1,
"accounts": [{
"id": 333,
"data": {
"name": "account1",
"createdAt": "2020-10-07T09:27:28.032Z"
}
}]
}, {
"id": 2,
"accounts": [{
"id": 334,
"data": {
"name": "account2",
"createdAt": "2020-10-06T09:27:28.032Z"
}
}, {
"id": 335,
"data": {
"name": "account3",
"createdAt": "2020-10-05T09:27:28.032Z"
}
}]
}]
const sorted = data.sort((a, b) => {
const aOldestDate = a.accounts.reduce((acc, item) => {
const itemDate = new Date(item.data.createdAt);
return itemDate < acc && itemDate || acc;
}, new Date());
const bOldestDate = b.accounts.reduce((acc, item) => {
const itemDate = new Date(item.data.createdAt);
return itemDate < acc && itemDate || acc;
}, new Date());
return aOldestDate - bOldestDate;
});
console.log(sorted);

Categories

Resources