Reputation: 26160
Given a collection (users
in the snippet below) with sub-collections, and another collection (organizations
) that contains properties I need merged into the sub-collection of users
, what is the most performant way to do so?
The code below works, but nested iterations never feel that great to me. Further, the production environment has hundreds / thousands of results, so performance is at least a consideration.
FYI, I'm leveraging the lodash library, and am aware some performance gain would be had from not using the library - however, I'm hoping someone can offer a more effective approach to the problem.
The code below looks up the name of the organization and then adds that name to the users
array for use in other parts of the app.
(The data structure is from an API, and cannot be changed.)
// organizations are actually fetched from an API via Observable. Can change at any time.
const organizations = [{
organization_id: 5,
organization_name: 'Sample 1'
},
{
organization_id: 6,
organization_name: 'Sample 2'
},
{
organization_id: 9,
organization_name: 'Sample 3'
},
// etc...
];
// users are actually fetched from an API via Observable. Can change at any time.
const users = [{
user_name: 'User 1',
organizations: [{
organization_id: 9,
organization_role: 'Limited'
},
{
organization_id: 6,
organization_role: 'Admin'
}
]
},
{
user_name: 'User 2',
organizations: [{
organization_id: 5,
organization_role: 'Limited'
},
{
organization_id: 6,
organization_role: 'Limited'
}
]
},
// etc...
];
document.addEventListener('DOMContentLoaded', () => {
_.forEach(users, (user) => {
_.forEach(user.organizations, (organization) => {
organization.organization_name = _.get(_.find(organizations, ['organization_id', organization.organization_id]), 'organization_name', '?');
});
});
console.log(users);
}, false);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Upvotes: 0
Views: 57
Reputation: 191996
Since _.find()
is an O(n) operation (where n is the length of organizations const), and the forEach operations O(m * l) (m number of users, l average number of organisations for each user), the total operation is O(n * m * l). You can lower it to O(n + m * l) by first mapping the organisations, which is an O(n) operation (using _.keyBy()
for example).
// organizations are actually fetched from an API via Observable. Can change at any time.
const organizations = [{"organization_id":5,"organization_name":"Sample 1"},{"organization_id":6,"organization_name":"Sample 2"},{"organization_id":9,"organization_name":"Sample 3"}];
// users are actually fetched from an API via Observable. Can change at any time.
const users = [{"user_name":"User 1","organizations":[{"organization_id":9,"organization_role":"Limited"},{"organization_id":6,"organization_role":"Admin"}]},{"user_name":"User 2","organizations":[{"organization_id":5,"organization_role":"Limited"},{"organization_id":6,"organization_role":"Limited"}]}];
document.addEventListener('DOMContentLoaded', () => {
const orgDict = _.keyBy(organizations, 'organization_id');
_.forEach(users, (user) => {
_.forEach(user.organizations, (organization) => {
organization.organization_name = _.get(orgDict['organization_id'], 'organization_name', '?');
});
});
console.log(users);
}, false);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Upvotes: 1