Need to remove duplication in array of objects and merge array with union USING JS.
trying to filter array
Just wanted to merge array["INTERFACE"] on the basis of APP_ID. and remove duplicate records.
unfiltered unmerged array!
var data = [
{
"APP_ID" : "1001",
"INTERFACE" : [
{
"INTERFACE_ID" : "01",
"NAME" : "CIF OPENNING",
"URL" : "/CusIdInfo",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "07",
"NAME" : "DASHBOARD",
"URL" : "/Dashboard",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "06",
"NAME" : "SUMMARY COPC",
"URL" : "/SummaryCopc",
"STATUS" : "A"
}
]
},
{
"APP_ID" : "1002",
"INTERFACE" : [
{
"INTERFACE_ID" : "07",
"NAME" : "DASHBOARD",
"URL" : "/Dashboard",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "08",
"NAME" : "BIOMETRIC",
"URL" : "/Biometric",
"STATUS" : "A"
}
]
},
{
"APP_ID" : "1001",
"INTERFACE" : [
{
"INTERFACE_ID" : "01",
"NAME" : "CIF OPENNING",
"URL" : "/CusIdInfo",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "05",
"NAME" : "SUMMARY",
"URL" : "/Summary",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "06",
"NAME" : "SUMMARY COPC 2",
"URL" : "/SummaryCopc2",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "07",
"NAME" : "DASHBOARD 2",
"URL" : "/Dashboard 2",
"STATUS" : "A"
}
]
},
{
"APP_ID" : "1002",
"INTERFACE" : [
{
"INTERFACE_ID" : "07",
"NAME" : "DASHBOARD",
"URL" : "/Dashboard",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "08",
"NAME" : "BIOMETRIC",
"URL" : "/Biometric",
"STATUS" : "A"
}
]
}
];
wanted result
[
{
"APP_ID" : "1002",
"INTERFACE" : [
{
"INTERFACE_ID" : "07",
"NAME" : "DASHBOARD",
"URL" : "/Dashboard",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "08",
"NAME" : "BIOMETRIC",
"URL" : "/Biometric",
"STATUS" : "A"
}
]
},
{
"APP_ID" : "1001",
"INTERFACE" : [
{
"INTERFACE_ID" : "01",
"NAME" : "CIF OPENNING",
"URL" : "/CusIdInfo",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "05",
"NAME" : "SUMMARY",
"URL" : "/Summary",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "06",
"NAME" : "SUMMARY COPC",
"URL" : "/SummaryCopc",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "07",
"NAME" : "DASHBOARD",
"URL" : "/Dashboard",
"STATUS" : "A"
}, {
"INTERFACE_ID" : "07",
"NAME" : "DASHBOARD 2",
"URL" : "/Dashboard2",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "06",
"NAME" : "SUMMARY COPC 2",
"URL" : "/SummaryCopc2",
"STATUS" : "A"
}
]
}
]
trying to filter array
Just wanted to merge array["INTERFACE"] on the basis of APP_ID. and remove duplicate records.
Here is a slightly elastic solution relying on function generators that allows dynamic aggregation.
The logic followed by the below example is that in your data input, the unique key of the main objects is APP_ID. Next, the aggregation rule of each APP_ID is that it should follow another aggregation rule for INTERFACE. Each interface, in fact, has a unique NAME, explaining why you have multiple "07" and "06" in your result sample.
The code explanation is documented in the code itself.
var data = [
{
"APP_ID" : "1001",
"INTERFACE" : [
{
"INTERFACE_ID" : "01",
"NAME" : "CIF OPENNING",
"URL" : "/CusIdInfo",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "07",
"NAME" : "DASHBOARD",
"URL" : "/Dashboard",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "06",
"NAME" : "SUMMARY COPC",
"URL" : "/SummaryCopc",
"STATUS" : "A"
}
]
},
{
"APP_ID" : "1002",
"INTERFACE" : [
{
"INTERFACE_ID" : "07",
"NAME" : "DASHBOARD",
"URL" : "/Dashboard",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "08",
"NAME" : "BIOMETRIC",
"URL" : "/Biometric",
"STATUS" : "A"
}
]
},
{
"APP_ID" : "1001",
"INTERFACE" : [
{
"INTERFACE_ID" : "01",
"NAME" : "CIF OPENNING",
"URL" : "/CusIdInfo",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "05",
"NAME" : "SUMMARY",
"URL" : "/Summary",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "06",
"NAME" : "SUMMARY COPC 2",
"URL" : "/SummaryCopc2",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "07",
"NAME" : "DASHBOARD 2",
"URL" : "/Dashboard 2",
"STATUS" : "A"
}
]
},
{
"APP_ID" : "1002",
"INTERFACE" : [
{
"INTERFACE_ID" : "07",
"NAME" : "DASHBOARD",
"URL" : "/Dashboard",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "08",
"NAME" : "BIOMETRIC",
"URL" : "/Biometric",
"STATUS" : "A"
}
]
}
];
// Aggregate duplicates with a common uniqueKey, invoking the aggregateExpression callback for each pair.
function* aggregateDuplicates(arr, uniqueKey, aggregateExpression) {
const aggregateGroups = arr.reduce((acc,next) => {
acc[next[uniqueKey]] = acc[next[uniqueKey]] || [];
return acc[next[uniqueKey]].push(next), acc;
}, {});
// loop items.
for (var [_, entries] of Object.entries(aggregateGroups)) {
// Aggregate results following the aggregateExpression.
yield Object.assign({}, entries.reduce((acc, next) => aggregateExpression(acc, next)));
}
}
// Aggregate duplicates of data, whose unique key is APP_ID.
const res = [...aggregateDuplicates(data, 'APP_ID', (a,b) => {
// In order to properly aggregate the INTERFACE property, acquire the set of entires interfaces of two items with the same APP_ID.
var interfacesSet = [...a.INTERFACE, ...b.INTERFACE];
// Finally, spread common values between them, then aggregate the INTERFACE property by its unique NAME key.
return Object.assign(a, b, {
INTERFACE: [...aggregateDuplicates(interfacesSet, 'NAME', (c,d) => {
// For that NAME property, just assign the values of both objects, nothing more nothing less.
return Object.assign(c,d)
})]
});
})];
console.log(res);
SIDE NOTE: The sorting to the INTERFACE property is not applied, this is a plus, but I don't think it's mandatory as long as the output data is effectively correct.
// Create the array of APP_ID
let idArr = data.map(val => val.APP_ID)
// Remove duplicate APP_ID
idArr = [...new Set(idArr)];
// Filter data according to unique APP_IDs
let newArr = idArr.map(val => {
return data.filter(value => value.APP_ID == val)[0]
})
console.log(newArr);
Solution
Here is a quick solution that I was able to come up with,
Note that this solution takes care of union of INTERFACES within the same APP_ID
const data = [
{
APP_ID: '1001',
INTERFACE: [
{
INTERFACE_ID: '01',
NAME: 'CIF OPENNING',
URL: '/CusIdInfo',
STATUS: 'A',
},
{
INTERFACE_ID: '07',
NAME: 'DASHBOARD',
URL: '/Dashboard',
STATUS: 'A',
},
{
INTERFACE_ID: '06',
NAME: 'SUMMARY COPC',
URL: '/SummaryCopc',
STATUS: 'A',
},
],
},
{
APP_ID: '1002',
INTERFACE: [
{
INTERFACE_ID: '07',
NAME: 'DASHBOARD',
URL: '/Dashboard',
STATUS: 'A',
},
{
INTERFACE_ID: '08',
NAME: 'BIOMETRIC',
URL: '/Biometric',
STATUS: 'A',
},
],
},
{
APP_ID: '1001',
INTERFACE: [
{
INTERFACE_ID: '01',
NAME: 'CIF OPENNING',
URL: '/CusIdInfo',
STATUS: 'A',
},
{
INTERFACE_ID: '05',
NAME: 'SUMMARY',
URL: '/Summary',
STATUS: 'A',
},
{
INTERFACE_ID: '06',
NAME: 'SUMMARY COPC 2',
URL: '/SummaryCopc2',
STATUS: 'A',
},
{
INTERFACE_ID: '07',
NAME: 'DASHBOARD 2',
URL: '/Dashboard 2',
STATUS: 'A',
},
],
},
{
APP_ID: '1002',
INTERFACE: [
{
INTERFACE_ID: '07',
NAME: 'DASHBOARD',
URL: '/Dashboard',
STATUS: 'A',
},
{
INTERFACE_ID: '08',
NAME: 'BIOMETRIC',
URL: '/Biometric',
STATUS: 'A',
},
],
},
];
const result = {};
data.forEach(elem => {
if (!result[elem.APP_ID]) {
result[elem.APP_ID] = {};
result[elem.APP_ID].APP_ID = elem.APP_ID;
result[elem.APP_ID].INTERFACE = elem.INTERFACE;
} else {
const interfaces = result[elem.APP_ID].INTERFACE;
for (const elemInterface of elem.INTERFACE) {
if (
!interfaces.some(inter => {
return elemInterface.INTERFACE_ID === inter.INTERFACE_ID;
})
) {
interfaces.push(elemInterface);
}
}
}
});
console.log('TCL: results', Object.values(result));
Assumptions:
Since you stated that you wanted union of the interfaces within the same APP_ID I assume that there should be no duplicate interfaces
Example: If there is an interface array A1,
[
{
INTERFACE_ID: '01',
NAME: 'CIF OPENNING',
URL: '/CusIdInfo',
STATUS: 'A',
},
{
INTERFACE_ID: '07',
NAME: 'DASHBOARD',
URL: '/Dashboard',
STATUS: 'A',
},
{
INTERFACE_ID: '06',
NAME: 'SUMMARY COPC',
URL: '/SummaryCopc',
STATUS: 'A',
},
]
and another interface array A2,
[
{
INTERFACE_ID: '01',
NAME: 'CIF OPENNING',
URL: '/CusIdInfo',
STATUS: 'A',
},
{
INTERFACE_ID: '05',
NAME: 'SUMMARY',
URL: '/Summary',
STATUS: 'A',
},
{
INTERFACE_ID: '06',
NAME: 'SUMMARY COPC 2',
URL: '/SummaryCopc2',
STATUS: 'A',
},
{
INTERFACE_ID: '07',
NAME: 'DASHBOARD 2',
URL: '/Dashboard 2',
STATUS: 'A',
},
]
Then A1 union A2 would be,
[
{
"INTERFACE_ID": "01",
"NAME": "CIF OPENNING",
"URL": "/CusIdInfo",
"STATUS": "A"
},
{
"INTERFACE_ID": "07",
"NAME": "DASHBOARD",
"URL": "/Dashboard",
"STATUS": "A"
},
{
"INTERFACE_ID": "06",
"NAME": "SUMMARY COPC",
"URL": "/SummaryCopc",
"STATUS": "A"
},
{
"INTERFACE_ID": "05",
"NAME": "SUMMARY",
"URL": "/Summary",
"STATUS": "A"
}
]
Note that there are no duplicates.
My second assumption is that when you check for duplicity in interfaces you use the INTERFACE_ID and not the whole interface object.
Example: Assume an interface object I1,
{
INTERFACE_ID: '01',
NAME: 'CIF OPENNING',
URL: '/CusIdInfo',
STATUS: 'A',
}
and another interface object I2 with the only difference being that it has a different status value which is 'B',
{
INTERFACE_ID: '01',
NAME: 'CIF OPENNING',
URL: '/CusIdInfo',
STATUS: 'B',
}
I am still considering I1 and I2 to be duplicates based on their INTERFACE_ID.
Suppose you want to compare entire object for duplicity then update your question and I shall change the answer to factor it in
Came up with this solution. Hope this works for you.
NOTE : In the expected result array you have 2 interface objects with same ID so i am assuming that two interface are duplicate only if all their properties match.
var data = [
{
"APP_ID" : "1001",
"INTERFACE" : [
{
"INTERFACE_ID" : "01",
"NAME" : "CIF OPENNING",
"URL" : "/CusIdInfo",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "07",
"NAME" : "DASHBOARD",
"URL" : "/Dashboard",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "06",
"NAME" : "SUMMARY COPC",
"URL" : "/SummaryCopc",
"STATUS" : "A"
}
]
},
{
"APP_ID" : "1002",
"INTERFACE" : [
{
"INTERFACE_ID" : "07",
"NAME" : "DASHBOARD",
"URL" : "/Dashboard",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "08",
"NAME" : "BIOMETRIC",
"URL" : "/Biometric",
"STATUS" : "A"
}
]
},
{
"APP_ID" : "1001",
"INTERFACE" : [
{
"INTERFACE_ID" : "01",
"NAME" : "CIF OPENNING",
"URL" : "/CusIdInfo",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "05",
"NAME" : "SUMMARY",
"URL" : "/Summary",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "06",
"NAME" : "SUMMARY COPC 2",
"URL" : "/SummaryCopc2",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "07",
"NAME" : "DASHBOARD 2",
"URL" : "/Dashboard 2",
"STATUS" : "A"
}
]
},
{
"APP_ID" : "1002",
"INTERFACE" : [
{
"INTERFACE_ID" : "07",
"NAME" : "DASHBOARD",
"URL" : "/Dashboard",
"STATUS" : "A"
},
{
"INTERFACE_ID" : "08",
"NAME" : "BIOMETRIC",
"URL" : "/Biometric",
"STATUS" : "A"
}
]
}
];
isInterfaceDuplicate = function(interface, app_id) {
var keys = Object.keys(interface);
var isDuplicate = false;
app_map[app_id].forEach(app_obj => {
var matched = true;
keys.forEach(key => {
if (interface[key] !== app_obj[key]) {
matched = false;
return;
}
});
if (matched) {
isDuplicate = true;
return;
}
});
return isDuplicate;
};
/* Create a mapping for APP_ID and INTERFACE */
var app_map = {};
data.forEach(app_obj => {
// If APP_ID is not present in map, then add in map directly.
if (!app_map[app_obj.APP_ID]) {
app_map[app_obj.APP_ID] = [...app_obj.INTERFACE];
return;
}
// If APP_ID is present in map, only add non duplicate interfaces in APP_ID key.
app_obj.INTERFACE.forEach(interface => {
var isDuplicate = isInterfaceDuplicate(interface, app_obj.APP_ID);
if (!isDuplicate) {
app_map[app_obj.APP_ID].push({...interface});
}
});
});
/* Create result array from the map */
var result = [];
Object.keys(app_map).forEach(app_id => {
result.push({
"APP_ID": app_id,
"INTERFACE": app_map[app_id]
});
});
console.log(result);
I have the following JSON file
var info = [{
"name" : "john",
"address" : "32 street, london",
"contact" : 123456
},{
"name" : "jeyy",
"address" : "51 street, new york",
"contact" : 987654321,
"gender" : "male"
},{
"name" : "robert",
"address" : "14th street, birmingham",
"contact" : 456123789,
"gender" : "male"
},{
"name" : "carlos",
"address" : "89th street, manchester",
"contact" : 23456
},{
"name": "johnny",
"address": "6th street, Washington",
"contact": 23456
},{
"name": "jack",
"address": "4th street, VA",
"contact": 23456,
"gender": "male"
}
];
As you can see I am missing "gender" = "male" object in some of the array. How can I add them in the missing object and not add them in an object which already have.
Also how would I get a new updated file.
Here I use forEach() to iterate through the array and check each object if it has a value in gender property. If it doesn't then give it a value "male".
var info = [{
"name" : "john",
"address" : "32 street, london",
"contact" : 123456
},{
"name" : "jeyy",
"address" : "51 street, new york",
"contact" : 987654321,
"gender" : "male"
},{
"name" : "robert",
"address" : "14th street, birmingham",
"contact" : 456123789,
"gender" : "male"
},{
"name" : "carlos",
"address" : "89th street, manchester",
"contact" : 23456
},{
"name": "johnny",
"address": "6th street, Washington",
"contact": 23456
},{
"name": "jack",
"address": "4th street, VA",
"contact": 23456,
"gender": "male"
}
];
info.forEach(i => {
if(!i.gender) i.gender = "male";
});
console.log(info);
You can use .hasOwnProperty on that object to find out which object don't have property gender and iteratively add it and write back into the file again!
Here's a code snippet to help you get started.
const fs = require('fs');
const util = require('util');
// Promisify fs api(s)
const readFileAsync = util.promisify(fs.readFile);
const writeFileAsync = util.promisify(fs.writeFile);
// IIFE to read the file, find the objects which has missing properties, add them and write them back
(async function() {
try {
const fileContents = await readFileAsync('data.json');
const fileData = JSON.parse(fileContents);
const remainingData = fileData.filter(x => !x.hasOwnProperty('gender'));
remainingData.forEach(x => x.gender = 'Male');
await writeFileAsync('data.json', JSON.stringify(fileData, null, 4));
} catch(err) {
console.log(`Failed because: {err}!`)
}
})();
This will solve-
var info = [{
"name" : "john",
"address" : "32 street, london",
"contact" : 123456
},{
"name" : "jeyy",
"address" : "51 street, new york",
"contact" : 987654321,
"gender" : "male"
},{
"name" : "robert",
"address" : "14th street, birmingham",
"contact" : 456123789,
"gender" : "male"
},{
"name" : "carlos",
"address" : "89th street, manchester",
"contact" : 23456
},{
"name": "johnny",
"address": "6th street, Washington",
"contact": 23456
},{
"name": "jack",
"address": "4th street, VA",
"contact": 23456,
"gender": "male"
}
];
info.forEach((e)=>{
var t=Object.keys(e);
if(t.indexOf('gender')==-1)
e.gender='male';
})
console.log(info);
I have that javascript object :
MyObject = [
{
"name" : "aaa",
"firstname" : "aaaaa"
},
{
"name" : "bbb",
"firstname" : "bbbb"
},
{
"name" : "cccc",
"firstname" : "" <--------- firstname is empty, but the element is not in the last
},
{
"name" : "ddd",
"firstname" : "dddd"
},
{
"name" : "eeee",
"firstname" : "" <--------- firstname is empty
},
{
"name" : "fffff",
"firstname" : "" <--------- firstname is empty
},
]
I want to delete the lastest lines that have "firstname" empty ... (a sort of trim) ... i dont want to remove all lines that have "firstname" empty... but just who are in the latestes lines. (that are in the bottom)
So, the result will be :
MyObject = [
{
"name" : "aaa",
"firstname" : "aaaaa"
},
{
"name" : "bbb",
"firstname" : "bbbb"
},
{
"name" : "cccc",
"firstname" : ""
},
{
"name" : "ddd",
"firstname" : "dddd"
}
]
Thank you
You can pop of at the end of the array as long as the firstname is empty
var MyObject = [{
"name": "aaa",
"firstname": "aaaaa"
}, {
"name": "bbb",
"firstname": "bbbb"
}, {
"name": "cccc",
"firstname": ""
}, {
"name": "ddd",
"firstname": "dddd"
}, {
"name": "eeee",
"firstname": ""
}, {
"name": "fffff",
"firstname": ""
}];
for (var i=MyObject.length;i--;) if (MyObject[i].firstname==="") MyObject.pop(); else break;
console.log(MyObject)
.as-console-wrapper {max-height: 100%!important; top: 0!important;}
Try this:
var MyObject = [
{
"name" : "aaa",
"firstname" : "aaaaa"
},
{
"name" : "bbb",
"firstname" : "bbbb"
},
{
"name" : "cccc",
"firstname" : ""
},
{
"name" : "ddd",
"firstname" : "dddd"
},
{
"name" : "eeee",
"firstname" : ""
},
{
"name" : "fffff",
"firstname" : ""
}
];
var i = MyObject.length;
while(true) {
if (!MyObject[--i].firstname) {
MyObject.pop();
} else {
break;
}
}
console.log(MyObject);