I have this Array with 6 different dates from db:
[{"_id":{"source":"2019-04-06","status":false},"count":1},
{"_id":{"source":"2019-04-06","status":true},"count":1},
{"_id":{"source":"2019-03-24","status":false},"count":2},
{"_id":{"source":"2019-03-24","status":true},"count":1},
{"_id":{"source":"2019-03-23","status":false},"count":3},
{"_id":{"source":"2019-03-08","status":false},"count":1},
{"_id":{"source":"2019-02-02","status":true},"count":1},
{"_id":{"source":"2019-02-02","status":false},"count":2},
{"_id":{"source":"2019-01-29","status":false},"count":1}]
What i need are 2 Arrays with the length of 6 items and the value of "count"
If only status "true" exists for a date, then i need to push a count: "0" to the false-array.
And if only status "false" exists for a date, then i need to push a count: "0" to the true-array.
It should look like this:
Arrayforstatusfalse = [1,2,3,1,2,1]
Arrayforstatustrue = [1,1,0,0,1,0]
But what i get is this:
Arrayforstatusfalse = [1,2,3,1,2,1]
Arrayforstatustrue = [1,1,1]
Update:
Sorry for this ugly code. i will be more precise. And thanks for your help.
this.responsedata = input
this.line1 = output for all the "false"
this.line2 = output for all the "true"
I loop over input data with condition and push it into the new arrays:
for (var i=0; i<this.responsedata.length;i++) {
if (this.responsedata[i]._id.status === true ) {
console.log('true exits for date: ' + JSON.stringify(this.responsedata[i]._id.source) + JSON.stringify(this.responsedata[i].count) )
this.line2.push(this.responsedata[i])
}
if (this.responsedata[i]._id.status === false ) {
console.log('false exits for date: ' + JSON.stringify(this.responsedata[i]._id.source) + JSON.stringify(this.responsedata[i].count) )
this.line1.push(this.responsedata[i])
}
}
Console :
[Log] false exits for date: "2019-04-06"1
[Log] true exits for date: "2019-04-06"1
[Log] false exits for date: "2019-03-24"2
[Log] true exits for date: "2019-03-24"1
[Log] false exits for date: "2019-03-23"3
[Log] false exits for date: "2019-03-08"1
[Log] true exits for date: "2019-02-02"1
[Log] false exits for date: "2019-02-02"2
[Log] false exits for date: "2019-01-29"1
[Log] line1[1,2,3,1,2,1]
[Log] line2[1,1,1]
And here i need line2 = [1,1,0,0,1,0]
because i need a 0 "if not exits on this date"..
You could take a Map for keeping the same index in insertation order of the given data.
var array = [{ _id: { source: "2019-04-06", status: false }, count: 1 }, { _id: { source: "2019-04-06", status: true }, count: 1 }, { _id: { source: "2019-03-24", status: false }, count: 2 }, { _id: { source: "2019-03-24", status: true }, count: 1 }, { _id: { source: "2019-03-23", status: false }, count: 3 }, { _id: { source: "2019-03-08", status: false }, count: 1 }, { _id: { source: "2019-02-02", status: true }, count: 1 }, { _id: { source: "2019-02-02", status: false }, count: 2 }, { _id: { source: "2019-01-29", status: false }, count: 1 }],
result = array.reduce((m => (r, { _id: { source, status }, count }) => {
var index = m.get(source);
if (index === undefined) {
m.set(source, index = m.size);
r.true[index] = 0;
r.false[index] = 0;
}
r[status][index] = count;
return r;
})(new Map), { true: [], false: [] }),
{ true: trues, false: falses } = result;
console.log(...trues);
console.log(...falses);
You can use reduce() to summarize the array into an object using the source as key. Convert the object into array using Object.entries and reduce it again to convert the inner child object into an array.
Use destructuring assignment syntax to assign into variables.
let array = [{"_id":{"source":"2019-04-06","status":false},"count":1},{"_id":{"source":"2019-04-06","status":true},"count":1},{"_id":{"source":"2019-03-24","status":false},"count":2},{"_id":{"source":"2019-03-24","status":true},"count":1},{"_id":{"source":"2019-03-23","status":false},"count":3},{"_id":{"source":"2019-03-08","status":false},"count":1},{"_id":{"source":"2019-02-02","status":true},"count":1},{"_id":{"source":"2019-02-02","status":false},"count":2},{"_id":{"source":"2019-01-29","status":false},"count":1}];
let {Arrayforstatusfalse,Arrayforstatustrue} = Object.entries(array.reduce((c, v) => {
c.Arrayforstatustrue[v._id.source] = c.Arrayforstatustrue[v._id.source] || 0;
c.Arrayforstatusfalse[v._id.source] = c.Arrayforstatusfalse[v._id.source] || 0;
if (v._id.status) c.Arrayforstatustrue[v._id.source] += v.count;
else c.Arrayforstatusfalse[v._id.source] += v.count;
return c;
}, {Arrayforstatusfalse: {},Arrayforstatustrue: {}}))
.reduce((c, [k, o]) => Object.assign(c, {[k]: Object.values(o)}), {});
console.log(Arrayforstatusfalse);
console.log(Arrayforstatustrue);
This?
const data = [
{"_id":{"source":"2019-04-06","status":false},"count":1},
{"_id":{"source":"2019-04-06","status":true},"count":1},
{"_id":{"source":"2019-03-24","status":false},"count":2},
{"_id":{"source":"2019-03-24","status":true},"count":1},
{"_id":{"source":"2019-03-23","status":false},"count":3},
{"_id":{"source":"2019-03-08","status":false},"count":1},
{"_id":{"source":"2019-02-02","status":true},"count":1},
{"_id":{"source":"2019-02-02","status":false},"count":2},
{"_id":{"source":"2019-01-29","status":false},"count":1},
];
const byDate = {};
data.forEach((f, ndx) => {
byDate[f._id.source] = byDate[f._id.source] || [];
byDate[f._id.source].push(f);
});
function mapCounts(byDate, status) {
return Object.values(byDate).map(d => {
const ndx = d.findIndex(e => e._id.status === status);
return ndx >= 0 ? d[ndx].count : 0;
});
}
const falseForDate = mapCounts(byDate, false);
const trueForDate = mapCounts(byDate, true);
console.log(falseForDate.join(','));
console.log(trueForDate.join(','));
note I'm curious what this is acutally for. The code above will not handle things if there are 3 of the same date because then there are would either be 2 counts for true or 2 for false. Which count to use. Similarly the same sitatuion arrises if their are 2 trues or 2 falses for the same date (same issue really). Maybe you want to sum the counts for true or false by date?
In that case
const data = [
{"_id":{"source":"2019-04-06","status":false},"count":1},
{"_id":{"source":"2019-04-06","status":true},"count":1},
{"_id":{"source":"2019-03-24","status":false},"count":2},
{"_id":{"source":"2019-03-24","status":true},"count":1},
{"_id":{"source":"2019-03-23","status":false},"count":3},
{"_id":{"source":"2019-03-08","status":false},"count":1},
{"_id":{"source":"2019-02-02","status":true},"count":1},
{"_id":{"source":"2019-02-02","status":false},"count":2},
{"_id":{"source":"2019-01-29","status":false},"count":1},
];
const byDate = {};
data.forEach((f, ndx) => {
byDate[f._id.source] = byDate[f._id.source] || [];
byDate[f._id.source].push(f);
});
function mapCounts(byDate, status) {
return Object.values(byDate).map(d => {
return d.reduce((acc, e) => acc + (e._id.status === status ? e.count : 0), 0);
});
}
const falseForDate = mapCounts(byDate, false);
const trueForDate = mapCounts(byDate, true);
console.log(falseForDate.join(','));
console.log(trueForDate.join(','));
or
const data = [
{"_id":{"source":"2019-04-06","status":false},"count":1},
{"_id":{"source":"2019-04-06","status":true},"count":1},
{"_id":{"source":"2019-03-24","status":false},"count":2},
{"_id":{"source":"2019-03-24","status":true},"count":1},
{"_id":{"source":"2019-03-23","status":false},"count":3},
{"_id":{"source":"2019-03-08","status":false},"count":1},
{"_id":{"source":"2019-02-02","status":true},"count":1},
{"_id":{"source":"2019-02-02","status":false},"count":2},
{"_id":{"source":"2019-01-29","status":false},"count":1},
];
const byDate = {};
data.forEach((f, ndx) => {
byDate[f._id.source] = byDate[f._id.source] || [0, 0];
byDate[f._id.source][f._id.status === true ? 1 : 0] += f.count;
});
const falseForDate = Object.values(byDate).map(v => v[0]);
const trueForDate = Object.values(byDate).map(v => v[1]);
console.log(falseForDate.join(','));
console.log(trueForDate.join(','));
You can use map to achieve this. They key of the map will be the source and value will be count. If no value found for a particular key, then assign 0. Otherwise assign value based on the given condition.
Iterate over all elements of inputArray. After the end of iteration, you will get two objects. Just take the values of the objects using Object.values() function.
You're done!!!
I have used ternary operator to make the code look short and easy. See the snippet below
var inputArray = [{"_id":{"source":"2019-04-06","status":false},"count":1},{"_id":{"source":"2019-04-06","status":true},"count":1},{"_id":{"source":"2019-03-24","status":false},"count":2},{"_id":{"source":"2019-03-24","status":true},"count":1},{"_id":{"source":"2019-03-23","status":false},"count":3},{"_id":{"source":"2019-03-08","status":false},"count":1},{"_id":{"source":"2019-02-02","status":true},"count":1},{"_id":{"source":"2019-02-02","status":false},"count":2},{"_id":{"source":"2019-01-29","status":false},"count":1}];
var trueObjects = {},
falseObjects = {};
inputArray.forEach(function(elem) {
var index = elem._id.source,
status = elem._id.status,
count = elem.count;
//initialize value for new index
trueObjects[index] = trueObjects[index] ? trueObjects[index] : 0;
falseObjects[index] = falseObjects[index] ? falseObjects[index] : 0;
//set value based on condition
trueObjects[index] = status ? count : trueObjects[index];
falseObjects[index] = !status ? count : falseObjects[index];
});
trueArray = Object.values(trueObjects);
falseArray = Object.values(falseObjects);
console.log(falseArray);
console.log(trueArray);
You can get unique sources (dates) and create true and false arrays for each source :
const dataArray = [{"_id":{"source":"2019-04-06","status":false},"count":1},
{"_id":{"source":"2019-04-06","status":true},"count":1},
{"_id":{"source":"2019-03-24","status":false},"count":2},
{"_id":{"source":"2019-03-24","status":true},"count":1},
{"_id":{"source":"2019-03-23","status":false},"count":3},
{"_id":{"source":"2019-03-08","status":false},"count":1},
{"_id":{"source":"2019-02-02","status":true},"count":1},
{"_id":{"source":"2019-02-02","status":false},"count":2},
{"_id":{"source":"2019-01-29","status":false},"count":1}];
// Get all sources
const sources = dataArray.map(item => item._id.source);
// Get unique sources
const uniqueSources = [...(new Set(sources))];
const arrayForStatusTrue = [];
const arrayForStatusFalse = [];
uniqueSources.forEach(source => {
// Check if source with status true exists
const itemWithStatusTrue = dataArray.find(item => (item._id.status && item._id.source === source));
itemWithStatusTrue ? arrayForStatusTrue.push(itemWithStatusTrue.count) : arrayForStatusTrue.push(0);
// Check if source with status false exists
const itemWithStatusFalse = dataArray.find(item => (!item._id.status && item._id.source === source));
itemWithStatusFalse ? arrayForStatusFalse.push(itemWithStatusFalse.count) : arrayForStatusFalse.push(0);
});
console.log(arrayForStatusTrue);
console.log(arrayForStatusFalse);
I would suggest using a Map to create one entry per date (source), which each would have two values representing the counts for both possible statuses (initialised with zero).
Then add the actual counts to those entries, and finally extract the data into the two arrays you expect:
// Sample input
const array = [{ _id: { source: "2019-04-06", status: false }, count: 1 }, { _id: { source: "2019-04-06", status: true }, count: 1 }, { _id: { source: "2019-03-24", status: false }, count: 2 }, { _id: { source: "2019-03-24", status: true }, count: 1 }, { _id: { source: "2019-03-23", status: false }, count: 3 }, { _id: { source: "2019-03-08", status: false }, count: 1 }, { _id: { source: "2019-02-02", status: true }, count: 1 }, { _id: { source: "2019-02-02", status: false }, count: 2 }, { _id: { source: "2019-01-29", status: false }, count: 1 }];
// Algorithm
const map = new Map(array.map(o => [o._id.source, [0,0]]));
array.forEach(o => map.get(o._id.source)[+o._id.status] += o.count);
const [noes, ayes] = [0, 1].map(i => Array.from(map.values(), a => a[i]));
// Output
console.log(JSON.stringify(noes), JSON.stringify(ayes));
Related
Iam having an array of object named finalArr and and object named replaceJsonData. If replaceJsonData contains add =1 , then value of REQUEST_TYPE in finalArr should also become 1
finalArr = [{
REQUEST_TYPE: 'add',
TIMESTAMP: '1671636661867',
}, ]
let replaceJsonData = {
"REQUEST_TYPE": {
'add': 1,
'modify': 2
}
}
I tried like this way , but value itself is in the form a key
finalArr.map((ele)=>{
Object.entries(replaceJsonData ).forEach(
([replaceDataKey, replaceDataValue]) => {
if (ele[replaceDataKey]) {
ele[replaceDataKey]=replaceDataValue
}
}
)
});
Expected Output:
finalArr = [{
REQUEST_TYPE: 1,
TIMESTAMP: '1671636661867',
}, ]
Use the property of replaceDataValue that matches the old value of the property being updated: replaceDataValue[ele[replaceDataKey]]
let finalArr = [{
REQUEST_TYPE: 'add',
TIMESTAMP: '1671636661867',
}, ]
let replaceJsonData = {
"REQUEST_TYPE": {
'add': 1,
'modify': 2
}
};
finalArr.map((ele) => {
Object.entries(replaceJsonData).forEach(
([replaceDataKey, replaceDataValue]) => {
if (ele[replaceDataKey]) {
ele[replaceDataKey] = replaceDataValue[ele[replaceDataKey]];
}
}
)
});
console.log(finalArr);
I have an Array full of transactions and I want to divide it by day. It will be an array of date that is and array of transations. It may be a little messy but I want to return this structure.
What I tried to do returns me the structure I want, but I don't know how to merge duplicated key values.
This is the array
const transactions = [
{
name: "Salário",
receiveDate: "2020-05-12T00:00:00.000Z",
value: "1000",
},
{
name: "Pagamento ",
receiveDate: "2020-05-12T00:00:00.000Z",
value: "2350",
},
{
name: "Passagem no VEM",
paidDate: "2020-05-02T00:00:00.000Z",
value: "130",
},
{
name: "Almoço",
paidDate: "2020-05-08T00:00:00.000Z",
value: "50",
},
];
This is what I already tried by now
const days = [];
const finalArray = [];
for (let i = 0; i < transactions.length; i++) {
transactions[i].day = transactions[i].receiveDate || transactions[i].paidDate;
days.push(transactions[i].day);
}
const datesToMatch = [...new Set(days)].map((date) => {
return { [date]: null };
});
transactions.map((transaction) => {
datesToMatch.map((dayObject) => {
const day = Object.keys(dayObject).toString();
if (day === transaction.day) {
finalArray.push({ [day]: [transaction] });
}
});
});
The output
[ { '2020-05-12T00:00:00.000Z': [ [Object] ] },
{ '2020-05-12T00:00:00.000Z': [ [Object] ] },
{ '2020-05-02T00:00:00.000Z': [ [Object] ] },
{ '2020-05-08T00:00:00.000Z': [ [Object] ] } ]
Expected output
[ { '2020-05-12T00:00:00.000Z': [ [Object, Object] ] },
{ '2020-05-02T00:00:00.000Z': [ [Object] ] },
{ '2020-05-08T00:00:00.000Z': [ [Object] ] } ]
Thanks!
Explanation:
dates : extract dates from both fields
uniqueDates : build a Set and convert it into an array so it only has uniqueDates
dateToTransactions : map every unique date to an object with one key (itself) and filter every transaction that is equal to it.
const transactions = [{
name: "Salário",
receiveDate: "2020-05-12T00:00:00.000Z",
value: "1000",
},
{
name: "Pagamento ",
receiveDate: "2020-05-12T00:00:00.000Z",
value: "2350",
},
{
name: "Passagem no VEM",
paidDate: "2020-05-02T00:00:00.000Z",
value: "130",
},
{
name: "Almoço",
paidDate: "2020-05-08T00:00:00.000Z",
value: "50",
},
];
const dates = transactions.map(x => {
const received = x.receiveDate || [];
const paid = x.paidDate || [];
return received + paid;
});
const uniqueDates = [...new Set(dates)];
const dateToTransactions =
uniqueDates.map(
date => {
sameDate = transactions.filter(x => x.receiveDate === date || x.paidDate == date);
return {[date]: sameDate};
});
console.log(dateToTransactions);
I would do something like this:
const days = [];
for (let i = 0; i < transactions.length; i++) {
transactions[i].day = transactions[i].receiveDate || transactions[i].paidDate;
days.push(transactions[i].day);
}
const result = new Map();
days.forEach((day) => {
result.set(day, [])
});
transactions.forEach((transaction) => {
let r = result.get(transaction.day);
r.push(transaction);
result.set(transaction.day, r);
});
Then, in the result map you have a list of the transactions that were made for each day.
This will give the result you expect
const days = {};
const finalArray = transactions.forEach((transaction) => {
let date = (transaction.receiveDate || transaction.paidDate)
if (!days[date]) { days[date] = [transaction]}
else {days[date].push(transaction)}
});
console.log(days);
I have an array:
let ar = [
{
uid:1,
flat_no: 1
},
{
uid:2,
flat_no: 2
},
{
uid:1,
flat_no:3
}
];
If uid are same then I want to remove duplicate uid and concatenate its flat_no. The output array should be like this:
[
{
uid:1,
flat_no: [1,3]
},
{
uid:2,
flat_no: 2
}
];
You can use a combination of Array.reduce and Array.find.
If you find an existing item in your accumulator array, just update it's flat_no property, otherwise push it to the accumulator array.
let arr = [
{
uid: 1,
flat_no: 1
},
{
uid: 2,
flat_no: 2
},
{
uid: 1,
flat_no: 3
}
]
arr = arr.reduce((arr, item) => {
const existing = arr.find(innerItem => innerItem.uid === item.uid)
if (existing) {
existing.flat_no = Array.isArray(existing.flat_no)
? existing.flat_no
: [existing.flat_no]
existing.flat_no.push(item.flat_no)
} else {
arr.push(item)
}
return arr
}, [])
console.log(arr)
You can iterate over your array and fill an object (used as a hashmap here).
Once done, you extract the values to get your result.
let hashResult = {}
ar.forEach(element => {
if (hashResult[element.uid] == undefined) {
hashResult[element.uid] = { uid: element.uid, flat_no: [] }
}
hashResult[element.uid].flat_no.push(element.flat_no)
})
let result = Object.values(hashResult)
console.log(new Date(), result)
You can do this in a concise way with a single Array.reduce and Object.values to match your desired output:
let data = [ { uid:1, flat_no: 1 }, { uid:2, flat_no: 2 }, { uid:1, flat_no:3 } ];
const result = data.reduce((r, {uid, flat_no}) => {
r[uid] ? r[uid].flat_no = [r[uid].flat_no, flat_no] : r[uid] = {uid, flat_no}
return r
}, {})
console.log(Object.values(result))
1)Reduce the initial array to an object which has uid as the key and the flat_no as the value.
2)Then run a map on the keys to convert it into an array of objects with uid and flat_no.
1) First Step Code
let ar = [{uid:1, flat_no: 1},{uid:2, flat_no: 2},{uid:1, flat_no:3}];
let outputObj = ar.reduce((outputObj,currObj,currIndex) => {
let {uid,flat_no} = currObj
if (outputObj[uid]) {
outputObj[uid].push(flat_no)
}
else {
outputObj[uid] = [flat_no]
}
return outputObj
},{})
2)
let finalOutput = Object.keys(outputObj).map(key =>
({uid:key,flat_no:outputObj[key]}))
console.log(finalOutput)
Using Array.reduce, I am trying to count the elements that have the same value for a specific property. I want to put the result in an array of objects containing a property for the value of the grouped by property and another one for the count. How can I do this easily in javascript ?
const CATEGORY = {
STRATEGY: 'STRATEGY',
CONTENT: 'CONTENT',
ADVERTISING: 'ADVERTISING',
MEASURMENT: 'MEASURMENT'
}
const lessons = [
{
title: 'ohoho',
category: CATEGORY.STRATEGY
}, {
title: 'hihihi',
category: CATEGORY.CONTENT
}, {
title: 'hello',
category: CATEGORY.CONTENT
}
]
let categoryLessonCount = lessons.reduce(function (acc, lesson) {
acc[lesson.category] ? acc[lesson.category]++ : acc[lesson.category] = 1
return acc
}, {})
console.log(categoryLessonCount[CATEGORY.STRATEGY])
console.log(categoryLessonCount[CATEGORY.CONTENT])
Actual categoryLessonCount value :
Object
{
STRATEGY: 1,
CONTENT: 2
}
Wanted categoryLessonCount value :
Array
[
{
title: 'STRATEGY',
count: 1
}, {
title: 'CONTENT',
count: 2
}
]
You already got the what you want just transform it into an array
const CATEGORY = {
STRATEGY: 'STRATEGY',
CONTENT: 'CONTENT',
ADVERTISING: 'ADVERTISING',
MEASURMENT: 'MEASURMENT'
}
const lessons = [{
title: 'ohoho',
category: CATEGORY.STRATEGY
}, {
title: 'hihihi',
category: CATEGORY.CONTENT
}, {
title: 'hello',
category: CATEGORY.CONTENT
}]
let count = lessons.reduce(function(acc, lesson) {
acc[lesson.category] ? acc[lesson.category] ++ : acc[lesson.category] = 1
return acc
}, {})
// transform count into what you want
let categoryLessonCount = [];
for (let cat in count) {
categoryLessonCount.push({
'title': cat,
'count': count[cat]
});
}
console.log(categoryLessonCount)
Something like this should work:
let categoryLessonCount = lessons.reduce(function(acc, lesson) {
let found = false
for (const item of acc) {
if (item.title === lesson.category) {
item.count++
found = true
}
}
if (!found) {
acc.push({
title: lesson.category,
count: 1
})
}
return acc
}, [])
Your main issue is that your accumulating an object but expecting an array (note the final argument to reduce).
Short solution using Object.keys and Array.prototype.map functions:
...
let categoryLessonCount = lessons.reduce(function (acc, lesson) {
acc[lesson.category] ? acc[lesson.category]++ : acc[lesson.category] = 1
return acc
}, {})
let counts = Object.keys(categoryLessonCount).map(
(k) => ({title: k, count: categoryLessonCount[k]})
)
console.log(counts);
Question:
How can I removal all emailAddress that are empty, and if there are no emailAddresses for an approval, remove that approval too.
My current solution will remove approvals when emailAddress completely empty. But not when two emailAddresses are present and one is empty (see script output vs. expected output)
var request = {
approvals: [
{
type: 'media',
emailAddresses: [
{emailAddress: 'frank#gmail.com'},
]
},
{
type: 'other',
emailAddresses: [
{emailAddress: ''},
]
},
{
type: 'scope',
emailAddresses: [
{emailAddress: 'kelly#yahoo.com'},
{emailAddress: ''},
]
}
]
}
const filterOutEmptyEmails = (approval) => {
if(approval.emailAddresses.filter(x => !!x.emailAddress).length){
return true;
}
}
let output = request.approvals.filter(filterOutEmptyEmails);
console.log(JSON.stringify(output));
// EXPECTED OUTPUT:
// approval: [
// {
// type: 'media',
// emailAddresses: [
// {emailAddress: 'frank#gmail.com'},
// ]
// },
// {
// type: 'scope',
// emailAddresses: [
// {emailAddress: 'kelly#yahoo.com'},
// ]
// }
// ]
// }]
Live Code
You are not replacing approval.emailAddresses in your code - you should use:
approval.emailAddresses = approval.emailAddresses.filter(x => !!x.emailAddress);
See demo below:
var request={approvals:[{type:'media',emailAddresses:[{emailAddress:'frank#gmail.com'},]},{type:'other',emailAddresses:[{emailAddress:''},]},{type:'scope',emailAddresses:[{emailAddress:'kelly#yahoo.com'},{emailAddress:''},]}]};
var filterOutEmptyEmails = (approval) => {
approval.emailAddresses = approval.emailAddresses.filter(x => !!x.emailAddress);
if(approval.emailAddresses.length){
return true;
}
}
var output = request.approvals.filter(filterOutEmptyEmails);
console.log(JSON.stringify(output));
EDIT:
Another proposal without mutating the input array - using Array.prototype.reduce to create a new array:
var request={approvals:[{type:'media',emailAddresses:[{emailAddress:'frank#gmail.com'},]},{type:'other',emailAddresses:[{emailAddress:''},]},{type:'scope',emailAddresses:[{emailAddress:'kelly#yahoo.com'},{emailAddress:''},]}]};
var output = request.approvals.reduce(function(p,c){
// creates a shallow copy
var elem = Object.assign({},c);
// replaces the reference to request.approvals by the new array created by the filter
elem.emailAddresses = elem.emailAddresses.filter(x => !!x.emailAddress);
if(elem.emailAddresses.length != 0)
p.push(elem);
return p;
},[]);
// console.log(request.approvals);
console.log(output);
.as-console-wrapper{top:0;max-height:100%!important;}
Possible "non mutation" solution could be like this
var request = {approvals: [{type: 'media',emailAddresses: [{emailAddress: 'frank#gmail.com'},]},{type: 'other',emailAddresses: [{emailAddress: ''},]},{type: 'scope', emailAddresses: [{emailAddress: 'kelly#yahoo.com'},{emailAddress: ''},]}]}
const filterOutEmptyEmails = (approval) => {
if(approval.emailAddresses.filter(x => !!x.emailAddress).length){
return true;
}
}
const output = request.approvals.map(approval => {
const filteredAproval = approval;
filteredAproval.emailAddresses = approval.emailAddresses.filter(x => !!x.emailAddress);
return filteredAproval
}).filter(filterOutEmptyEmails);
console.log(JSON.stringify(output));
console.log(JSON.stringify(request));
Without mutation (with lots of ES6/7 sugar):
const filteredApprovals = request.approvals.reduce((acc, approval) => {
const filteredEmailAddresses = approval.emailAddresses.filter(item => item.emailAddress);
return (filteredEmailAddresses.length > 0) ? [...acc, { ...approval, emailAddresses: filteredEmailAddresses }] : acc;
}, []);
Fiddle: https://jsfiddle.net/free_soul/hndjbce3/