I'm trying to find an efficient and short-as-possible way to collapse near-identical objects in an array into objects containing their own arrays with the nonidentical data. It sounds complicated when I try to explain it, let me rather show you what I mean:
I have an array of objects that looks like the following:
[{
id: '6b6574cf-d77a-4ed8-852f-cb60a0d377cd',
first_name: 'SomeName',
email: 'some@email.com',
rName: 'User', // 0,1
rAuthority: 'ROLE_USER', // 0,1
pId: 'e7da65a9-ea2d-4c77-82f6-e1addc78fb6e',
pMobile: '012 345 6789',
atId: '90db0c5d-3030-44aa-9dc0-40242af0d5c5', // 0,2
atPlatform: 'web',
},{
id: '6b6574cf-d77a-4ed8-852f-cb60a0d377cd',
first_name: 'SomeName',
email: 'some@email.com',
rName: 'User', // 0,1
rAuthority: 'ROLE_USER', // 0,1
pId: 'e7da65a9-ea2d-4c77-82f6-e1addc78fb6e',
pMobile: '012 345 6789',
atId: 'e7d53cab-a9b9-40ae-9271-11d79c2f269c', // 1,3
atPlatform: 'web',
},{
id: '6b6574cf-d77a-4ed8-852f-cb60a0d377cd',
first_name: 'SomeName',
email: 'some@email.com',
rName: 'Admin', // 2,3
rAuthority: 'ROLE_ADMIN', // 2,3
pId: 'e7da65a9-ea2d-4c77-82f6-e1addc78fb6e',
pMobile: '012 345 6789',
atId: '90db0c5d-3030-44aa-9dc0-40242af0d5c5', // 0,2
atPlatform: 'web',
},{
id: '6b6574cf-d77a-4ed8-852f-cb60a0d377cd',
first_name: 'SomeName',
email: 'some@email.com',
rName: 'Admin', // 2,3
rAuthority: 'ROLE_ADMIN', // 2,3
pId: 'e7da65a9-ea2d-4c77-82f6-e1addc78fb6e',
pMobile: '012 345 6789',
atId: 'e7d53cab-a9b9-40ae-9271-11d79c2f269c', // 1,3
atPlatform: 'web',
}]
// I point out which of the properties are not identical by adding
// quotes showing which indices of the array contains unique values of
// said property. If the there's not a quote to the right of the
// property it's identical across all indices.
I want to transform this array into an array where objects with duplicate ids are collapsed into one object with object arrays containing the nonidentical data. It looks like this:
[{
id: '6b6574cf-d77a-4ed8-852f-cb60a0d377cd',
first_name: 'SomeName',
email: 'some@email.com',
roles: [{
name: 'User',
authority: 'ROLE_USER'
},{
name: 'Admin',
authority: 'ROLE_ADMIN'
}],
profiles: [{
id: 'e7da65a9-ea2d-4c77-82f6-e1addc78fb6e',
mobile: '012 345 6789',
}],
tokens: [{
id: '90db0c5d-3030-44aa-9dc0-40242af0d5c5',
platform: 'web',
},{
id: 'e7d53cab-a9b9-40ae-9271-11d79c2f269c',
platform: 'web',
}]
}]
As you can see, all the properties from the previous array that had a prefix r
now all have their own objects in an array in the roles
property. p
prefixed properties are in profiles
and at
prefixed properties are in tokens
. An object is considered to be "identical" if it has the same id
as another object.
Here's some code I've written that seems to successfully transform the first array into the second array:
...then(data => {
let users = [];
// gets the correct formatting
data.forEach((d, i) => {
let found = false;
users.forEach((u, j) => {
if(d.id === u.id) {
u.roles.push({ name:d.rName, authority:d.rAuthority });
u.tokens.push({ id:d.atId, platform:d.atPlatform });
u.profiles.push({ id:d.pId, mobile:d.pMobile });
found = true;
}
});
if(!found) {
users.push({
id:d.id,
first_name:d.first_name,
email:d.email,
roles: [{ name:d.rName, authority:d.rAuthority }],
profiles: [{ id:d.pId, mobile:d.pMobile }],
tokens: [{ id:d.atId, platform:d.atPlatform }]
});
}
});
// remove duplicates from sub-arrays
users.forEach((user, i) => {
user.roles = _.uniqBy(user.roles, 'name');
user.profiles = _.uniqBy(user.profiles, 'id');
user.tokens = _.uniqBy(user.tokens, 'id');
});
});
I have two problems with this code. The first is that it's super long (I actually removed many properties from the first array for the sake of this question - in reality, each object has more than double the amount of properties you see here, making this code much longer), and the second is that I've got a strong suspicion that it's probably very inefficient.
Question:
Can someone please help me rewrite the code that I'm using to format my array into something shorter and more efficient. I do have lodash installed so I'd prefer answers that made use of it, but I'll gladly also accept vanilla.js answers.
Additional notes:
This question is a follow-up to another question I posted. Looking at this question will vaguely show you where the data I'm trying to transform in this question comes from. The short version is that it comes from the database, it's my idea of lazy loading using Knex.js. The idea is that that each User can have multiple Roles, Profiles and AuthTokens.