How to iterate an object and build a new one - javascript

I am using JavaScript to iterate customers in an object which is constructed as follows:
[
{
"customer": "Customer 1",
"project": "1"
},
{
"customer": "Customer 2",
"project": "2"
},
{
"customer": "Customer 2",
"project": "3"
}
]
I wish to build a new object in iteration which would be constructed like this:
[
{
"Customer 1": {
"projects": "1"
}
},
{
"Customer 2": {
"projects": [
"2",
"3"
]
}
}
]
Any tips how this could be achieved?

You can create an intermediate object to form the inner level object. Use the iterator on that object to form the array out of it.
Please refer below for sample code.
var response = [
{
"customer": "Customer 1",
"project": "1"
},
{
"customer": "Customer 2",
"project": "2"
},
{
"customer": "Customer 2",
"project": "3"
}
];
var length = response.length,
i = 0,
result = {},
j = 0,
finalResult = [];
for(;i<length;i++){
var eachObj = response[i];
if(!result[response[i].customer]){
result[response[i].customer] = [response[i].project];
}
else{
result[response[i].customer].push(response[i].project);
}
}
for(var key in result){
var eachObj = [];
eachObj[key] = result[key];
finalResult.push(eachObj);
}
console.log(finalResult);

Lookup in new array for customer and if found add project, otherwise add customer.
var data = [
{
"customer": "Customer 1",
"project": "1"
},
{
"customer": "Customer 2",
"project": "2"
},
{
"customer": "Customer 2",
"project": "3"
}
];
var newData = [];
data.forEach(function (el, i) {
var customer = newData.filter(function (ell) {
return el.customer === ell.customer;
})[0];
if (customer) {
customer.projects.push(el.project);
} else {
newData.push({ customer: el.customer, projects: [el.project] });
}
});
document.write('<pre>' + JSON.stringify(newData, null, 4) + '</pre>');

Related

Rename keys in reduce function

I am essentially receiving data from another API that takes the following structure
const ob = {
"dataOne": [
{
"type": "Type 1",
"name": "email.failed"
},
{
"type": "Type 1",
"name": "email.success"
},
{
"type": "Type 2",
"name": "email.success"
},
{
"type": "Type 3",
"name": "email.success"
},
],
};
What I was doing what creating a new array which essentially gets each unique type and then does a total count and an individual count of each unique name.
I also have another data set I combine with this but omitted for this question.
The working code I have is
const ob = {
"dataOne": [
{
"type": "Type 1",
"name": "email.failed"
},
{
"type": "Type 1",
"name": "email.success"
},
{
"type": "Type 2",
"name": "email.success"
},
{
"type": "Type 3",
"name": "email.success"
},
],
};
const dataReduced = ob.dataOne.reduce((acc, o) => {
if (!acc[o.type]) {
acc[o.type] = [
{
count: 0,
'email.success': 0,
'email.failed': 0,
},
];
}
acc[o.type][0].count = (acc[o.type][0].count || 0) + 1;
acc[o.type][0][o.name] = acc[o.type][0][o.name] + 1;
return acc;
}, {});
console.log(dataReduced);
What I can't figure out however, because it is matching on email.success is how to rename these in my final output. I essentially want to remove the email. part.
So instead, the console.log should be
{
Type 1: [{
count: 2,
failed: 1,
success: 1
}],
Type 2: [{
count: 1,
failed: 0,
success: 1
}],
Type 3: [{
count: 1,
failed: 0,
success: 1
}]
}
How would I achieve this?
Thanks
You can do something like this
const ob = {
"dataOne": [
{
"type": "Type 1",
"name": "email.failed"
},
{
"type": "Type 1",
"name": "email.success"
},
{
"type": "Type 2",
"name": "email.success"
},
{
"type": "Type 3",
"name": "email.success"
},
],
};
const dataReduced = ob.dataOne.reduce((acc, o) => {
const name = o.name.replace('email.', '')
if (!acc[o.type]) {
acc[o.type] = [
{
count: 0,
'success': 0,
'failed': 0,
},
];
}
acc[o.type][0].count = (acc[o.type][0].count || 0) + 1;
acc[o.type][0][name] = acc[o.type][0][name] + 1;
return acc;
}, {});
console.log(dataReduced);
I've no clue why the console output is actually in your Browser console and not in this JS Constainer, but here, no reduce, but I don't even see the reason why a reduce would be better here:
var arr = [
{
"type": "Type 1",
"name": "email.failed"
},
{
"type": "Type 1",
"name": "email.success"
},
{
"type": "Type 2",
"name": "email.success"
},
{
"type": "Type 3",
"name": "email.success"
},
];
var result = [];
for (var o of arr) {
if (!result.hasOwnProperty(o.type)) {
var newObj = {
count: 1,
failed: 0,
success: 0,
};
if (o.name.indexOf('failed') !== -1) {
newObj.failed++;
}
if (o.name.indexOf('success') !== -1) {
newObj.success++;
}
result[o.type] = [newObj];
} else {
result[o.type][0].count++;
if (o.name.indexOf('failed') !== -1) {
result[o.type][0].failed++;
}
if (o.name.indexOf('success') !== -1) {
result[o.type][0].success++;
}
}
}
console.log(result);
I resolved this using the for in loop:
for(let elem in dataReduced){
dataReduced[elem][0]['success'] = dataReduced[elem][0]['email.success'];
dataReduced[elem][0]['failed'] = dataReduced[elem][0]['email.failed'];
delete dataReduced[elem][0]['email.success'];
delete dataReduced[elem][0]['email.failed'];
}

Empty array when filter inside deep an object

I made this function to filter in deep an array of object, but at the end the result is empty. If i check with console.log inside the if statement , it show me filtered object, but resultPost return me empty value. I also tryed to push inside an empty array the filtered value, but not work.
const post = [{
"name": "new post",
"description": "simple desc",
"taxonomies": {
"categories": {
"0": {
"term_id": 15
},
"1": {
"term_id": 20
},
}
}
},
{
"name": "new post 2",
"description": "simple desc 2",
"taxonomies": {
"categories": {
"0": {
"term_id": 11
},
"1": {
"term_id": 12
},
}
}
}
];
const filterID = [15, 1];
const resultPost = post.filter(post => {
if ((post.taxonomies.categories.filter(postct => postct.term_id === filterID)).length > 0) return post
});
console.log(resultPost);
You could filter the posts by matching the taxonomies.categories[id].term_id as follows:
const post = [{
"name": "new post",
"description": "simple desc",
"taxonomies": {
"categories" : {
"0" : {
"term_id" : 15
},
"1" : {
"term_id" : 20
},
}
}
},
{
"name": "new post 2",
"description": "simple desc 2",
"taxonomies": {
"categories" : {
"0" : {
"term_id" : 11
},
"1" : {
"term_id" : 12
},
}
}
}];
const filterID = [15,1];
const resultPost = post.filter(item => {
const { categories } = item.taxonomies;
return Object.keys(categories).reduce((cats, id) => {
filterID.includes(categories[id].term_id) && cats.push(id);
return cats;
}, []).length
});
console.log( resultPost)
Like said in comments, you can't use filter on an Object.
Try this instead
const resultPost = post.filter(post => {
for (let cat in post.taxonomies.categories) { // one way to loop over objects
// filterId is an array so you can't just use ===
if (filterID.includes(post.taxonomies.categories[cat].term_id)) return true;
}
return false;
});
Inside filter, you can take Object.values of that object and then use some based on your condition to filter out records. Something like this:
const post = [{ "name": "new post", "description": "simple desc", "taxonomies": { "categories": { "0": { "term_id": 15 }, "1": { "term_id": 20 }, } } }, { "name": "new post 2", "description": "simple desc 2", "taxonomies": { "categories": { "0": { "term_id": 11 }, "1": { "term_id": 12 }, } } }];
const filterID = [15,1];
const result = post.filter(p=>Object.values(p.taxonomies.categories).some(n=>filterID.includes(n.term_id)));
console.log(result);

how Grouping JSON objects in .dmc file?

I have this sample of JSON :
{
"sending": {
"field": [
{
"email": "Sample String",
"id": 1234,
"name": "Sample String"
}, {
"email": "Sample String",
"id": 1234,
"name": "Sample String"
},{
"email": "Sample String",
"id": 1111,
"name": "Sample String"
}
]
}
}
I want to converted JSON to be grouping by id like this:
{
"sending": {
"field": [
{
"1234": [
{
"name": "Sample String",
"email": "Sample String"
},{
"name": "Sample String",
"email": "Sample String"
}
]
},
{
"1111": [
{
"name": "Sample String",
"email": "Sample String"
}
]
}
]
}
}
I wrote this code in .dmc file but it does not work as I want :
map_S_root_S_root = function(){
var outputroot={};
var a = 0;
outputroot = {};
outputroot.sending = {};
outputroot.sending.field = [];
for(i_field_1d3104f4_e7ee_449b_9653_ccc4f8985491 in inputroot.sending.field){
outputroot.sending.field[a] = {};
id = inputroot.sending.field[i_field_1d3104f4_e7ee_449b_9653_ccc4f8985491].id;
outputroot.sending.field[a].id = [];
var c =0;
for(i in outputroot.sending.field[c].id){
if (inputroot.sending.field[i_field_1d3104f4_e7ee_449b_9653_ccc4f8985491].id === outputroot.sending.field[c].id){
outputroot.sending.field[c].id[c] += inputroot.sending.field[i_field_1d3104f4_e7ee_449b_9653_ccc4f8985491].name;
}
c++
}
outputroot.sending.field[a].id[a] = {};
outputroot.sending.field[a].id[a].name = inputroot.sending.field[i_field_1d3104f4_e7ee_449b_9653_ccc4f8985491].name;
outputroot.sending.field[a].id[a].email = inputroot.sending.field[i_field_1d3104f4_e7ee_449b_9653_ccc4f8985491].email;
a++;
}
return outputroot;
};
I use WSO2 data mapper mediator and write the code in .dmc file (data mapper configuration file ) in integration studio , could anyone help? Thanks
You can reduce it.
var array={ "sending": { "field": [ { "email": "Sample String", "id": 1234, "name": "Sample String" }, { "email": "Sample String", "id": 1234, "name": "Sample String" },{ "email": "Sample String", "id": 1111, "name": "Sample String" } ] }};
array.sending.field = array.sending.field.reduce((acc,{id, ...rest})=>{
acc[id] =acc[id] || [];
acc[id].push(rest);
return acc;
},{});
console.log(array);
The answer is
result = {
"field": [{
"id": "11",
"name": "asma",
"email": "asma#hotmail"
}, {
"id": "11",
"name": "jone",
"email": "jone#hotmail"
}, {
"id": "1234",
"name": "jak",
"email": "jak#hotmail"
}]
}
results = result.field;
groups = {};
for (var i in results) {
var groupName = results[i].id;
if (!groups[results[i].id]) {
groups[groupName] = [];
}
groups[groupName].push({"name" :results[i].name,"email":results[i].email})
}
console.log(groups);

Filtration of multilevel JSON array

I am trying to duplicate value only one time as well as unique from my JSON array.
I have tried the following code.
return_data = {};
return_data.planner = [{
"date": "2019-08-30T12:10:08.000Z",
"event": [{
"name": "Event 1",
"color": "#ccccc"
}]
},
{
"date": "2019-09-30T10:10:08.000Z",
"event": [{
"name": "Event 5",
"color": "#ccccc"
},
{
"name": "Event 4",
"color": "#ccccc"
},
{
"name": "Event 3",
"color": "#ccccc"
}
]
},
{
"date": "2019-09-30T10:10:08.000Z",
"event": [{
"name": "Event 5",
"color": "#ccccc"
},
{
"name": "Event 4",
"color": "#ccccc"
},
{
"name": "Event 3",
"color": "#ccccc"
}
]
},
{
"date": "2019-09-30T10:10:08.000Z",
"event": [{
"name": "Event 5",
"color": "#ccccc"
},
{
"name": "Event 4",
"color": "#ccccc"
},
{
"name": "Event 3",
"color": "#ccccc"
}
]
}
];
res.header('Content-Type', 'application/json');
res.send(JSON.stringify(return_data));
Using above json array:
var u_array = [];
var tem = JSON.parse(JSON.stringify(return_data.response.planner));
for (var i = 0; i < tem.length; i++) {
console.log(tem[i].date);
var status = true;
for (var j = 0; j < u_array.length; j++) {
if (u_array[j].date == tem[i].date) {
status = false;
break;
}
}
if (status) {
u_array.push(tem[i]);
}
};
return_data.response.planner = u_array;
I expect the duplicate value only one time with unique values.
There are many different ways to do what you need. You can follow this thread for some pointers.
Here's one way to get distinct-
/**
* inputArray = Input array
* keySelector = A function to select which key should be used to determine if element is distinct
* keepFirstMatch =
* true - If there is a matching element, and you want to keep the first original item
* false - If there is a matching element and you want to override the original item so that it gets overwritten by latest value in the array
*/
function getDistinct(inputArray, keySelector, keepFirstMatch = false) {
const result = inputArray.reduce((acc, curr) => {
if (keepFirstMatch) {
if (typeof (acc[keySelector(curr)]) === 'undefined') {
acc[keySelector(curr)] = curr;
}
} else {
acc[keySelector(curr)] = curr;
}
return acc;
}, {});
return Object.keys(result).map(k => result[k]);
}
let distinct = getDistinct(planner, (c) => c.date);

Javascript map is not a function what trying to read data

I am trying to populate a chart so I'm getting the data into 2 lists in order to do this.
This is the data:
var data = [{
"id": "622",
"name": "some name",
"boats": {
"637": {
"id": "637",
"name": " Subcat 1",
"translations": null
},
"638": {
"id": "638",
"name": "Subcat 2",
"translations": null
}
},
"image": "73e043a7fae04b55855bede22da6286b"
}];
And I am running this code in order to populate the lists:
var chList = [];
var boatList = [];
var boatCount = [];
for (var i = 0; i < data.length; i++) {
var obj = data[i];
var cl = obj.name + " [" + obj.id + "]";
if (obj.boats != null) {
chList.push(cl);
}
if(obj.boats) {
var nme = obj.boats.map( function(item){
return item.name;
});
boatList = boatList.concat(nme);
boatCount.push(nme.length);
}
}
console.log(boatList);
console.log(boatCount);
My problem is that I keep getting:
TypeError: obj.boats.map is not a function
How can I fix this?
Note: The data is actually this:
{
"id": "622",
"name": "some name",
"boats": {
"637": {
"id": "637",
"name": " Subcat 1",
"translations": null
},
"638": {
"id": "638",
"name": "Subcat 2",
"translations": null
}
},
"image": "73e043a7fae04b55855bede22da6286b"
};
But I added [ and ] to it in order to use data.length and the lists where empty too ... Do I then leave this data as it is?
The problem is that obj.boats is an object, not an array, hence doesn't have the map method.
Try this instead:
Object.keys(obj.boats).map(function(k) { return obj.boats[k].name; });
See MDN
boats is an object, not an array. Map is for arrays.
You could use a for ( in ) loop or Object.keys() to get an array of keys and work with that.
The two other answers are right, I'd change the data though:
"boats": [
{
"id": "637",
"name": " Subcat 1",
"translations": null
},
{
"id": "638",
"name": "Subcat 2",
"translations": null
}
],
Using the id as key and then giving the containing object a "id" property is kinda pointless. When you change the data to this structure your code will work fine.
Besides all other answers that already correctly point to obj.boats being an Object and not an Array, I'd like providing a solution that demonstrates the elegant beauty of Array.reduce ...
var boatChartData = [{
"id": "622",
"name": "some name",
"boats": {
"637": {
"id": "637",
"name": "Subcat 1",
"translations": null
},
"638": {
"id": "638",
"name": "Subcat 2",
"translations": null
}
},
"image": "73e043a7fae04b55855bede22da6286b"
}, {
"id": "623",
"name": "other name",
"boats": {
"639": {
"id": "639",
"name": "Supercat",
"translations": null
},
"640": {
"id": "640",
"name": "Supercat II",
"translations": null
},
"641": {
"id": "641",
"name": "Supercat III",
"translations": null
}
},
"image": "73e043a7fae04b55855bede22da6295c"
}];
function collectBoatChartData(collector, chartItem/*, idx, list*/) {
var
boatNameList,
boatMap = chartItem.boats;
if (boatMap != null) {
collector.chartItemTitleList.push([
chartItem.name,
" [",
chartItem.id,
"]"
].join(""));
boatNameList = Object.keys(boatMap).map(collector.getBoatNameByKey, boatMap);
collector.boatNameList = collector.boatNameList.concat(boatNameList);
//collector.chartItemBoatNameList.push(boatNameList);
collector.chartItemBoatCountList.push(boatNameList.length);
}
return collector;
}
var processedBoatChartData = boatChartData.reduce(collectBoatChartData, {
getBoatNameByKey: function (key) {
return this[key].name;
},
boatNameList: [],
chartItemTitleList: [],
//chartItemBoatNameList: [],
chartItemBoatCountList: []
});
console.log("processedBoatChartData.boatNameList : ", processedBoatChartData.boatNameList);
console.log("processedBoatChartData.chartItemTitleList : ", processedBoatChartData.chartItemTitleList);
//console.log("processedBoatChartData.chartItemBoatNameList : ", processedBoatChartData.chartItemBoatNameList);
console.log("processedBoatChartData.chartItemBoatCountList : ", processedBoatChartData.chartItemBoatCountList);
Note
Taking into account the OP's additional comment, mentioning the provided axample's real data structure, the above provided solution of mine just changes to ...
var boatChartData = {
"id": "622",
"name": "some name",
"boats": {
"637": {
"id": "637",
"name": "Subcat 1",
"translations": null
},
"638": {
"id": "638",
"name": "Subcat 2",
"translations": null
}
},
"image": "73e043a7fae04b55855bede22da6286b"
};
var processedBoatChartData = [boatChartData].reduce(collectBoatChartData, {
getBoatNameByKey: function (key) {
return this[key].name;
},
boatNameList: [],
chartItemTitleList: [],
//chartItemBoatNameList: [],
chartItemBoatCountList: []
});
.., proving that generic solutions can be recycled/adapted easily, if e.g. data structures do change.

Categories

Resources