DEV Community

druchan
druchan

Posted on

Enrich an object - Javascript Recipe

This scenario is very common in apps that interact with data from an API/backend service.

Let's say you get a customers list which looks like this:

let customers = [ { id: 1, name: 'john', age: 28, city: 'denver' }, { id: 2, name: 'bob', age: 25, city: 'kyoto' }, { id: 3, name: 'angela', age: 44, city: 'mumbai' }, ]; 
Enter fullscreen mode Exit fullscreen mode

And then you get, as an example, a kycCustomer:

let kycCustomer = { customerId: 1, kyc: true, createdOn: '2022-11-01', }; 
Enter fullscreen mode Exit fullscreen mode

But when I want to use the kycCustomer to, say, show on the UI or use as input to another function, I have to also get the customer's name, age and city where customerId equals 1, and "enrich" this kycCustomer object with that data.

To do this, I use an enrich function where I tell which keys to match, which keys to extract and the function returns an enriched list.

const enrich = ({ match, extract = [], source = [] }) => (inputObj) => { if (!match) return inputObj; if (!extract?.length) return inputObj; if (!source) return inputObj; if (!source?.length) return inputObj; let matchingItem = source.find( (s) => s[match.sourceKey] === inputObj[match.inputKey] ); if (!matchingItem) return inputObj; return extract.reduce((acc, key) => { return { ...acc, [key]: matchingItem[key], }; }, inputObj); }; // USAGE let customers = [ { id: 1, name: 'john', age: 28, city: 'denver' }, { id: 2, name: 'bob', age: 25, city: 'kyoto' }, { id: 3, name: 'angela', age: 44, city: 'mumbai' }, ]; let kycCustomer = { customerId: 1, kyc: true, createdOn: '2022-11-01', }; let result = enrich({ match: { sourceKey: 'id', inputKey: 'customerId' }, extract: ['name', 'age', 'city'], source: customers, })(kycCustomer); /* result = { customerId: 1, kyc: true, createdOn: '2022-11-01', name: 'john', age: 28, city: 'denver' } */ 
Enter fullscreen mode Exit fullscreen mode

Handling lists instead of objects

We handled a single object kycCustomer but what if we have to enrich an entire list/array of such objects?

let kycCustomers = [ { customerId: 1, kyc: true, createdOn: '2022-11-01' }, { customerId: 2, kyc: false }, { customerId: 3, kyc: true, createdOn: '2022-09-01' }, ]; 
Enter fullscreen mode Exit fullscreen mode

Simply mapping over and using the enrich function will solve this for us. Like so:

let customers = [ { id: 1, name: 'john', age: 28, city: 'denver' }, { id: 2, name: 'bob', age: 25, city: 'kyoto' }, { id: 3, name: 'angela', age: 44, city: 'mumbai' }, ]; let kycCustomers = [ { customerId: 1, kyc: true, createdOn: '2022-11-01' }, { customerId: 2, kyc: false }, { customerId: 3, kyc: true, createdOn: '2022-09-01' }, ]; let enrichedKycCustomers = kycCustomers.map((kycCustomer) => enrich({ match: { sourceKey: 'id', inputKey: 'customerId' }, extract: ['name', 'age', 'city'], source: customers, })(kycCustomer) ); /* enrichedKycCustomers = [ { customerId: 1, kyc: true, createdOn: '2022-11-01', name: 'john', age: 28, city: 'denver', }, { customerId: 2, kyc: false, name: 'bob', age: 25, city: 'kyoto' }, { customerId: 3, kyc: true, createdOn: '2022-09-01', name: 'angela', age: 44, city: 'mumbai', }, ] */ 
Enter fullscreen mode Exit fullscreen mode

And in fact, because enrich is a higher-order function (notice how it takes one argument and returns a function that takes the inputObject argument), we can also condense the enrichedKycCustomers to this:

let enrichedKycCustomers = kycCustomers.map( enrich({ match: { sourceKey: 'id', inputKey: 'customerId' }, extract: ['name', 'age', 'city'], source: customers, }) ); 
Enter fullscreen mode Exit fullscreen mode

Top comments (2)

Collapse
 
artydev profile image
artydev

Great series thank you :-)

Collapse
 
zomars profile image
Omar López

This is exactly what I was looking for! I'm going to try to recreate it in TypeScript. Wish me luck.