How to convert object into array of object using reduce? - javascript

I want to convert object into array of object that fits my needs. I prefer using the most simple solution and smaller amount of code to write. The json is stored inside "monitorings" variable.
monitorings = [
{
"id": 1,
"survey_id": 1,
"region_id": 9101,
"month_id": 1,
"target": 22,
"progress": 22,
"survey": {
"name": "HPG",
"category": "SHP"
},
},
{
"id": 2,
"survey_id": 1,
"region_id": 9102,
"month_id": 1,
"target": 10,
"progress": 10,
"survey": {
"name": "SHPED",
"category": "SHPED"
},
},
}
]
My brain can only think until this code
Object.entries(
monitorings.reduce((monitorings, monitoring) => {
const { name } = monitoring.survey
monitorings[name] = monitorings[name]
? [...monitorings[name], monitoring]
: [monitoring]
return monitorings
}, {})
)
actual output
[
"survey.name", [{grouped object}],
"survey.name", [{grouped object}],
]
expected output
[
"survey.category", [
"survey.name", [{grouped object}],
"survey.name", [{grouped object}],
]
,
"survey.category", [
"survey.name", [{grouped object}],
"survey.name", [{grouped object}],
],
]
Thanks for your help
- Edit -
grouped object's format has the same format as the original object like below
[
{
"id": 2,
"survey_id": 1,
"region_id": 9102,
"month_id": 1,
"target": 10,
"progress": 10,
"survey": {
"name": "SHPED",
"category": "SHPED"
},
},
{same format as above},
{same format as above},
...
],

i found the answer here and modify it.
Object.entries(monitorings.reduce((map, obj) => {
!map[obj.survey["category"]]
? map[obj.survey["category"]] = {}
: [].concat(obj.survey["name"]).forEach(subEl => {
!map[obj.survey["category"]][subEl]
? map[obj.survey["category"]][subEl] = []
: map[obj.survey["category"]][subEl].push(obj);
})
return map;
}, {})
)
explanation
//return convert object into array of object
Object.entries(
//return new form of object
monitorings.reduce((map, obj) => {
//if empty
!map[obj.survey["category"]]
//create new empty object of survey["category"]
? map[obj.survey["category"]] = {}
//else combine all of returned object of survey["name"] into empty array of object
: [].concat(obj.survey["name"])
//iterate over obj.survey["name"]
.forEach(subEl => {
//if that object is empty
!map[obj.survey["category"]][subEl]
//create empty array of survey["category"][subEl]
? map[obj.survey["category"]][subEl] = []
//else push every element of filtered original JSON into array of survey["category"][subEl]
: map[obj.survey["category"]][subEl].push(obj);
})
//return grouped object
return map;
}, {})
)

Related

Insert new JSON objects in nested JS array based on condition

For one of my e-commerce application requirement, I have a nested array of the form (Sample):
const data = [
{
"id": 1,
"group": "upper-wear",
"labels": [
{
"type": "shirts",
"quantity": "20",
},
],
popular: true
},
{
"id": 2,
"group": "bottom-wear",
"lables": [
{
"type": "trousers",
"quantity": "31",
},
],
popular: true
},
]
To this array, I need to insert new objects to the array 'labels' if the group value equals 'upper-wear'.
const newDataToInsert = [
{
"type": 'blazers',
"quantity": 19
},
]
This is what I tried so far, considering that for now I only need to insert to single label (i.e. 'upper-wear') (in future, there can be multiple labels category 'upper-wear', 'bottom-wear', to be inserted into):
const updatedArray = data.map((datum) => {
if (datum.group === 'upper-wear') {
return {
...datum,
labels: [...datum.labels, ...newDataToInsert]
};
}
});
console.log(updatedArray);
But there seems to be a silly issue that I am missing as the result returns like this:
[
{
id: 1,
group: 'upper-wear',
labels: [ [Object], [Object] ],
popular: true
},
undefined
]
I know there may be better approaches available, but this is what I can think of as the minimum solution for now.
any help to resolve the current or any better solution will be highly appreciated.
Try with this
updatedArray = data.map((d) => {
if (d.group && d.group === 'upper-wear') {
return { ...d, labels: d.labels.concat(newDataToInsert) }
} else {
return d;
}
})
const data = [
{
"id": 1,
"group": "upper-wear",
"labels": [
{
"type": "shirts",
"quantity": "20",
},
],
popular: true
},
{
"id": 2,
"group": "bottom-wear",
"lables": [
{
"type": "trousers",
"quantity": "31",
},
],
popular: true
},
];
const newDataToInsert = [
{
"type": 'blazers',
"quantity": 19
},
];
const updatedArray = data.map((d) => {
if (d.group && d.group === 'upper-wear') {
return { ...d, labels: d.labels.concat(newDataToInsert) }
} else {
return d;
}
});
console.log(updatedArray)
Explaination
Here while mapping the data, we check for the condition
IF
If it matches then we will first copy the whole object from the variable b return { ...b }
after that we take another variable with the same name lables return { ...d, labels: d.labels.concat(newDataToInsert) },As per the JSON default nature the new variable with the same name will hold the latest value
Here in labels we first take a copy of old data and then merge it with newDataToInsert array labels: d.labels.concat(newDataToInsert), It will merge 2 arrays and store them in JSON with the name labels
Else
In else we just return the current values else { return d; }
You don't actually need to iterate with map over the array. Just find an object in the array and change what you want.
const data=[{id:1,group:"upper-wear",labels:[{type:"shirts",quantity:"20"}],popular:true},{id:2,group:"bottom-wear",lables:[{type:"trousers",quantity:"31"}],popular:true}];
const newDataToInsert=[{type:"blazers",quantity:19}];
data.find(({ group }) => group === 'upper-wear')?.labels.push(...newDataToInsert);
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You're not returning all objects from your map. you're only returning a result when your criteria is met. This is resulting in your undefined objects...
const data = [
{ "id": 1, "group": "upper-wear", "labels": [ { "type": "shirts", "quantity": "20", }, ], popular: true },
{ "id": 2, "group": "bottom-wear", "lables": [ { "type": "trousers", "quantity": "31", }, ], popular: true },
]
const newDataToInsert = [ { "type": 'blazers',"quantity": 19 }, ]
const updatedArray = data.map(datum => {
if (datum.group === 'upper-wear') datum.labels = [...datum.labels, ...newDataToInsert]
return datum
});
console.log(updatedArray);
You can use Array#find to locate the desired group and then change labels for the group found. There are two options depending on how many items you would like to insert. Use Array#push to add the desired item; use forEach for more than one item:
const searchgroup = "upper-wear";
const target = data.find(({group}) => group === searchgroup);
target.labels.push(...newDataToInsert); //For one item to insert
//newDataToInsert.forEach(label => target.labels.push( label )); //For more than one item
const data = [{"id": 1, "group": "upper-wear", "labels": [{"type": "shirts", "quantity": "20"},],popular: true }, {"id": 2, "group": "bottom-wear", "lables": [{"type": "trousers", "quantity": "31", },],popular: true}];
const newDataToInsert = [{"type": 'blazers', "quantity": 19}];
//group to find
const searchgroup = "upper-wear";
//target element in data
const target = data.find(({group}) => group === searchgroup);
//check if group was found
if( target ) {
//if there's only one product in newDataToInsert us this:
//target.labels.push(...newDataToInsert);
//if you have more than one product to be inserted use this; also works for one
newDataToInsert.forEach(label => target.labels.push( label ));
} else {
console.log( `No such group found: ${searchgroup}!` );
}
console.log( data );

How to convert this Array to Object

I can't seem to find the answer, how to change array in array to object in array ..??
problem this in javaScript. How to convert? How to convert?
I have this array.
[
"or",
[
"or",
{
"status": 1
},
{
"verified": 1
}
],
[
"and",
{
"social_account": 1
},
{
"enable_social": 1
}
]
]
I want this object:
{
"or": [
{
"or": [
{
"status": 1
},
{
"verified": 1
}
]
},
{
"and": [
{
"social_account": 1
},
{
"enable_social": 1
}
]
}
]
}
You can use a recursive function. The base case is when the argument is not an array. In the other case, extract the first array value as key for the object, and map the rest of the array via the recursive function:
const convert = data => Array.isArray(data) && ["or","and"].includes(data[0])
? { [data[0]]: data.slice(1).map(convert) }
: data;
// demo:
let data = ["or",
["or", {"status": 1}, {"verified": 1}],
["and",{"social_account": 1}, {"enable_social": 1}]
];
console.log(convert(data));

Check If Array Has Value in Angular

I have to check if any of the "cuesData" has a value or length greater than 0.
In my code below, i can only check the first array but not the others.
TS
checkValues(values) {
const result = Object.values(values).every((value) => value[1].cuesData.length > 0);
return result;
}
HTML
<div *ngIf="checkValues(values) === true">
JSON
[
[
"videoData__1",
{
"id": 1,
"title": "Pale Blue Dot",
"stoppedAt": 97.834667,
"cuesData": [
{
"startTime": 25.335678,
"endTime": 35.335678,
"description": "fqff"
}
]
}
],
[
"videoData__2",
{
"id": 2,
"title": "Big Buck Bunny",
"stoppedAt": 247.57881,
"cuesData": []
}
],
[
"videoData__3",
{
"id": 3,
"title": "Elephants Dream",
"stoppedAt": 404.585327,
"cuesData": []
}
]
]
Change,
checkValues(values) {
const result = Object.values(values).every((value) => value[1].cuesData.length > 0);
return result;
}
To
checkValues(values){
const result = Object.values(values).some((value) => value[1].cuesData.length > 0);
return result;
}
Working Stackblitz: https://stackblitz.com/edit/my-angular-starter-j4yypu
Here .every() method will check that all conditions should met but whereas some() method works that at least one condition has been true..
Stackblitz without cuesdata length: https://stackblitz.com/edit/my-angular-starter-cfpxa5
You can use some method for this:
*ngIf="CheckValues(values)"
function:
CheckValues(values : any[]){
return values.some(v=>v[1].cuesData&&v[1].cuesData.length); //if any array has cuesData, some will return true
}
more about some : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some

How to access a specific element in nested array in JSON data using JavaScript?

I have JSON data which is structured as below. Intension is to look up a specific datapoint, e.g. annual profit, which is 5000.
I want to do this by finding the column by name, e.g. "profit", identify the column index (3 in the example), and then use the column index to select the nth (3rd) element in the second node ("annual") of the "data" array.
How can I do this using the findIndex() function in Javascript (see the key part of my code below)?
JSON data:
{
"datatable": {
"data": [
[
"AAPL",
"quarterly",
1000,
2000
],
[
"AAPL",
"annual",
5000,
10000
]
],
"columns": [{
"name": "ticker"
"type": "String"
},
{
"name": "timedim"
"type": "String"
},
{
"name": "profit",
"type": "Integer"
},
{
"name": "revenue",
"type": "Integer"
}
]
}
}
JavaScript code:
// daten contains the "data" array of the JSON dataset
// spalten contains the "columns" array of the JSON dataset
var i = spalten.findIndex(obj => obj.name == "profit");
output += '<p>Annual profit AAPL: ' + daten[i] + '</p>';
elroot.innerHTML += output;
You have 2-dimensional array, so, you need two indexes:
const json = {
"datatable": {
"data": [
[
"AAPL",
"quarterly",
1000,
2000
],
[
"AAPL",
"annual",
5000,
10000
]
],
"columns": [{
"name": "ticker",
"type": "String"
},
{
"name": "timedim",
"type": "String"
},
{
"name": "profit",
"type": "Integer"
},
{
"name": "revenue",
"type": "Integer"
}
]
}
}
var profitIndex = json.datatable.columns.findIndex(item => item.name == 'profit');
var annualIndex = json.datatable.data.findIndex(array => array.indexOf('annual') > -1);
var annualProfit = json.datatable.data[annualIndex][profitIndex];
If you need a function, it could look like below:
var getValueFromJson = function (json, columnName, dataMarker) {
var columnIndex = json.datatable.columns.findIndex(item => item.name == columnName);
var dataMarkerIndex = json.datatable.data.findIndex(array => array.indexOf(dataMarker) > -1);
if (columnIndex < 0 || dataMarkerIndex < 0) {
return null;
}
return json.datatable.data[dataMarkerIndex][columnIndex];
}
console.log(getValueFromJson(json, 'profit', 'quarterly'));
console.log(getValueFromJson(json, 'profit', 'annual'));
console.log(getValueFromJson(json, 'revenue', 'quarterly'));
console.log(getValueFromJson(json, 'revenue', 'annual'));
Above code prints:
> 1000
> 5000
> 2000
> 10000
Based on the JSON structure you've given, the following will work. Writing a function would be good if you want to get specific profit based on parameters.
var output = ""
function getProfit(type="annual", column=2) {
var arrForType = yourData.datatable.data.find(arr => arr.indexOf(type) !== -1);
return arrForType[column];
}
var i = yourData.datatable.columns.findIndex(obj => obj.name == "profit");
output += '<p>Annual profit AAPL: ' + getProfit("annual", i) + '</p>';
document.body.innerHTML += output;
You don't need findIndex - just use find and includes like so:
const data = {
"datatable": {
"data": [
[
"AAPL",
"quarterly",
1000,
2000
],
[
"AAPL",
"annual",
5000,
10000
]
],
"columns": [{
"name": "ticker",
"type": "String"
},
{
"name": "timedim",
"type": "String"
},
{
"name": "profit",
"type": "Integer"
},
{
"name": "revenue",
"type": "Integer"
}
]
}
};
function findValue(type) {
return data.datatable.data.find(e => e.includes(type))[2];
}
console.log(findValue("annual"));
console.log(findValue("quarterly"));
This is the basic idea, then if you need to scale obviously you'll need to do this in a nicer way.
let output = '';
// Searches the desired index (refactor as needed)
const index = spalten.findIndex(obj => obj.name == "profit")
// Extract all the profits (if you dont need all just select the desired one)
daten.map(item => output += `<p>${item[1]} profit ${item[0]}: ${item[index]}</p>`)

Array Map using JS - Compare values to another array and return value from second array

I'd like to map this table's chapter_id and brother_id with the brothers and chapters table below and return the brothername and name field's respectively. Using js or jquery. I am using vuejs returning minutes array as a computed property. See below.
In sql it's be something like
select brothername from brothers where minute.brother_id = brothers.id ... and then set the brothername as the new value for brother_id
same thing goes for chapter_id:
select brothername from brothers where minute.brother_id = brothers.id ... and then set the brothername as the new value for brother_id
the resulting array or object should be:
Expected Array
[
{
"location":"UCLA",
"chapter_id":"Beta",
"brother_id":"Golpher",
"created_at":"2008-05-15 22:23:00",
"status":"Approved"
},
{ ... },
{
"location":"John's Deli",
"chapter_id":"Beta", notice the change in the array based on the ids
"brother_id":"Sheera", notice the change in the array based on the ids
"created_at":"2008-05-15 22:23:00",
"status":"Approved"
}
]
Minutes Table (original array)
[
{
"location":"UCLA",
"chapter_id":2,
"brother_id":1,
"created_at":"2008-05-15 22:23:00",
"status":"Approved"
},
{ ... },
{
"location":"John's Deli",
"chapter_id":2,
"brother_id":4,
"created_at":"2008-05-15 22:23:00",
"status":"Approved"
}
]
Chapter's Table
[
{
"id":1,
"letter_representation":"A",
"name":"Alpha",
"founded_at":"UCLA",
...
},
{ ... }
]
Brother's Table
[
{
"id":1,
"profile_id":1,
"chapter_id":1,
"brothername":"Golpher",
"firstname":"Jack",
...
},
{ ... },
{
"id":4,
"profile_id":4,
"chapter_id":1,
"brothername":"Sheera",
"firstname":"Jake",
...
}
]
Vue.js
computed: {
brothers () {
return this.$store.state.brothers
},
chapters () {
return this.$store.state.chapters
},
minutes () {
return this.$store.getters.model
}
},
I assume that you don't want to mutate objects in the original arrays with this operation.
Note You may want to handle the case where brother_id or chapter_id doesn't exist in the corresponding table. In the below example, it just sets the property value to undefined
const minutesTable = [{
"location": "UCLA",
"chapter_id": 2,
"brother_id": 1,
"created_at": "2008-05-15 22:23:00",
"status": "Approved"
}, {
"location": "John's Deli",
"chapter_id": 2,
"brother_id": 4,
"created_at": "2008-05-15 22:23:00",
"status": "Approved"
}]
const chapterTable = [{
"id": 1,
"letter_representation": "A",
"name": "Alpha",
"founded_at": "UCLA",
}]
const brotherTable = [{
"id": 1,
"profile_id": 1,
"chapter_id": 1,
"brothername": "Golpher",
"firstname": "Jack",
}, {
"id": 4,
"profile_id": 4,
"chapter_id": 1,
"brothername": "Sheera",
"firstname": "Jake",
}]
// your result
const result = minutesTable.map(m => {
const brother = brotherTable.find(b => b.id === m.brother_id)
const chapter = chapterTable.find(c => c.id === m.chapter_id)
return Object.assign({}, m, {
brother_id: brother && brother.brothername,
chapter_id: chapter && chapter.name,
})
})
console.log(result)
This should be what you need
const minutesTable = [
{
"location":"UCLA",
"chapter_id":2,
"brother_id":1,
"created_at":"2008-05-15 22:23:00",
"status":"Approved"
},
{
"location":"John's Deli",
"chapter_id":2,
"brother_id":4,
"created_at":"2008-05-15 22:23:00",
"status":"Approved"
}
]
const chapterTable =
[
{
"id":1,
"letter_representation":"A",
"name":"Alpha",
"founded_at":"UCLA",
}
]
const brotherTable = [
{
"id":1,
"profile_id":1,
"chapter_id":1,
"brothername":"Golpher",
"firstname":"Jack",
},
{
"id":4,
"profile_id":4,
"chapter_id":1,
"brothername":"Sheera",
"firstname":"Jake",
}
]
/* code starts here */
let newMinutesTable = JSON.parse(JSON.stringify(minutesTable)).map(a => {
let brother = brotherTable.find(id => id.id === a.brother_id);
let chapter = chapterTable.find(id => id.id === a.chapter_id)
if (brother) a.brother_id = brother.brothername
if (chapter) a.chapter_id = chapter.name;
return a;
})
console.log([minutesTable,newMinutesTable]);
I think you should prepare those values first just to better understanding. So I made this, let me explain in pieces.
Your input information:
var minutesTable = [{
"location": "UCLA",
"chapter_id": 2,
"brother_id": 1,
"created_at": "2008-05-15 22:23:00",
"status": "Approved"
}, {
"location": "John's Deli",
"chapter_id": 2,
"brother_id": 4,
"created_at": "2008-05-15 22:23:00",
"status": "Approved"
}],
chapterTable = [{
"id": 1,
"letter_representation": "A",
"name": "Alpha",
"founded_at": "UCLA",
}],
brotherTable = [{
"id": 1,
"profile_id": 1,
"chapter_id": 1,
"brothername": "Golpher",
"firstname": "Jack",
}, {
"id": 4,
"profile_id": 4,
"chapter_id": 1,
"brothername": "Sheera",
"firstname": "Jake",
}];
Somehow you'll be forced to take this information as variables. We will work with that.
Preparing data
Dealing with array of objects it's a litle bit complicated when you need to look for unique informations on each object from distinct arrays especially if you want to run this more than once. So instead of working with arrays of objects we can save our lifes changing that to objects of objects, where each item index must be that unique IDs. Look:
var chapters = {},
brothers = {};
chapterTable.map(function(el, i) {
chapters[el.id] = el;
});
brotherTable.map(function(el, i) {
brothers[el.id] = el;
});
Now you can easily find a chapter by chapter_id or a brother by brother_id, right? Then you can finish the problem like this:
var output = [];
minutesTable.map(function(el, i) {
var item = {
"location": el.location, // note that values are just default values, just in case
"chapter_id":"-",
"brother_id":"-",
"created_at": el.created_at,
"status": el.status
};
// PS: you need to check if that brother_id really exists!
if(brothers[el.brother_id] != undefined) {
item.brother_id = brothers[el.brother_id].brothername;
}
// PS: the same with chapters
if(chapters[el.chapter_id] != undefined) {
item.chapter_id = chapters[el.chapter_id].name;
}
output.push(item);
});
That's it. Anyway, if you can change your SQL queries, would be better to work with SQL joins and prepare your values there.

Categories