Clint_A
Clint_A

Reputation: 536

Push JS object array to another object array with matching object key

I have a bunch of objects from multiple sources that I'd like to merge so I can work with one large object instead of say 5 or 10 objects.

Let's say my main object array with employees basic data that I'd like to push the other arrays to is

var employees = [
{emp_id: 1, emp_name: "John D", phone:"123456"},
{emp_id: 2, emp_name: "Mary J", phone:"234567"},
{emp_id: 3, emp_name: "Doe J", phone:"345678"},
{emp_id: 4, emp_name: "Jane M", phone:"456789"}
]

And another object array with the employees work history:

var employee_history = [
{emp_id: 1, company: "ABC", Years: 4},
{emp_id: 2, company: "BCD", Years: 3},
{emp_id: 3, company: "CDE", Years: 2},
{emp_id: 4, company: "DEF", Years: 1}
]

And a final object array with the employees residential history as:

var cities_lived = [
{emp_id: 1, city: "Moscow", Years: 1},
{emp_id: 1, city: "Doha", Years: 1},
{emp_id: 2, city: "Cairo", Years: 2},
{emp_id: 2, city: "London", Years: 1},
{emp_id: 3, city: "Tunis", Years: 2},
{emp_id: 3, city: "Beijing", Years: 2},
{emp_id: 4, city: "New York", Years: 1},
{emp_id: 4, city: "Capetown", Years: 1}
]

So I'd like to push employee_history and cities_lived into the individual objects inside employees using the emp_id property to match and have an output like this or something close as long as it's inside the individual object:

[
{
emp_id: 1, 
emp_name: "John D", 
phone: "123456", 
company: "ABC", 
Years: 4, 
cities: [
    {emp_id: 1, city: "Doha", Years: "1"}, 
    {emp_id: 1, city: "Doha", Years: "1"}
] 
},
{},
{},
...
]

How can I achieve this?

My cumbersome solution was to loop each object array and create new objects which I'd push the data to, then finally push the results into the main object array. But I don't like the idea of having to do all that manually and even then I'm not sure how to push the results into the main object array where the emp_id properties match.

Upvotes: 1

Views: 1504

Answers (3)

HMR
HMR

Reputation: 39250

You could try to write small functions that do little and combine them into one that will merge items into an item.

Then take all your data that needs to be merged with their merger function and reduce employees to a new value that has everything merged.

const employees = [{"emp_id":1,"emp_name":"John D","phone":"123456"},{"emp_id":2,"emp_name":"Mary J","phone":"234567"},{"emp_id":3,"emp_name":"Doe J","phone":"345678"},{"emp_id":4,"emp_name":"Jane M","phone":"456789"}];
const employee_history = [{"emp_id":1,"company":"ABC","Years":4},{"emp_id":2,"company":"BCD","Years":3},{"emp_id":3,"company":"CDE","Years":2},{"emp_id":4,"company":"DEF","Years":1}];
const cities_lived = [{"emp_id":1,"city":"Moscow","Years":1},{"emp_id":1,"city":"Doha","Years":1},{"emp_id":2,"city":"Cairo","Years":2},{"emp_id":2,"city":"London","Years":1},{"emp_id":3,"city":"Tunis","Years":2},{"emp_id":3,"city":"Beijing","Years":2},{"emp_id":4,"city":"New York","Years":1},{"emp_id":4,"city":"Capetown","Years":1}];
const whatever = [{ emp_id: 1, whatever: 'whatever' }];//extra to merge item

//merges items with the merger function from toMerge array in uniqueArray 
//  if they match using matcher 
const mergeIn = (uniqueArray, toMerge, matcher, merger) =>
  uniqueArray.map((item) =>
    merger(item, toMerge.filter(matcher(item))),
  );
//create a merger function set item[itemFieldName] with a mapped result 
//  of others using mapper function
const merger = (itemFieldName, mapper) => (
  item,
  others,
) => ({
  ...item,
  [itemFieldName]: others.map(mapper),
});
//match on emp_id
const matchEpmId = (item) => (other) =>
  item.emp_id === other.emp_id;

console.log(
  [
    [
      cities_lived,
      //merger function that sets item.cities with others mapped to {city,Years}
      merger('cities', ({ city, Years }) => ({ city, Years}))
    ],
    [
      employee_history,
      //merger function that sets item.history with others mapped to {company,Years}
      merger('history', ({ company, Years }) => ({ company, Years}))
    ],
    [
      whatever,//extra to merge items
      merger('whatever', ({ whatever }) => whatever),
    ],
  ].reduce(
    (result, [other, merger]) =>
      mergeIn(result, other, matchEpmId, merger),
    employees,
  ),
);

Upvotes: 1

Muhammad Jahanzeb
Muhammad Jahanzeb

Reputation: 186

Yes, that is simple to do. You just need to iterate over employees and build the object along the way and at the end of loop you will have the desired result.

var employees = [
  { emp_id: 1, emp_name: "John D", phone: "123456" },
  { emp_id: 2, emp_name: "Mary J", phone: "234567" },
  { emp_id: 3, emp_name: "Doe J", phone: "345678" },
  { emp_id: 4, emp_name: "Jane M", phone: "456789" }
];


var employee_history = [
  { emp_id: 1, company: "ABC", Years: 4 },
  { emp_id: 2, company: "BCD", Years: 3 },
  { emp_id: 3, company: "CDE", Years: 2 },
  { emp_id: 4, company: "DEF", Years: 1 }
];

var cities_lived = [
  { emp_id: 1, city: "Moscow", Years: 1 },
  { emp_id: 1, city: "Doha", Years: 1 },
  { emp_id: 2, city: "Cairo", Years: 2 },
  { emp_id: 2, city: "London", Years: 1 },
  { emp_id: 3, city: "Tunis", Years: 2 },
  { emp_id: 3, city: "Beijing", Years: 2 },
  { emp_id: 4, city: "New York", Years: 1 },
  { emp_id: 4, city: "Capetown", Years: 1 }
];

employees.forEach(employee => {
  const employeeHistory = employee_history.find(x => x.emp_id == employee.emp_id);
  employee = { ...employee, ...employeeHistory };
  const employeeCities = cities_lived.filter(x => x.emp_id === employee.emp_id);
  employee.cities = [];

  if (employeeCities && employeeCities.length > 0) {
    employee.cities = employeeCities;
  }
});

Upvotes: 1

front_end_dev
front_end_dev

Reputation: 2056

You need to iterate over cities and history array and create a map by emp_id as key. And insert into final object.

Try this

var employees = [
{emp_id: 1, emp_name: "John D", phone:"123456"},
{emp_id: 2, emp_name: "Mary J", phone:"234567"},
{emp_id: 3, emp_name: "Doe J", phone:"345678"},
{emp_id: 4, emp_name: "Jane M", phone:"456789"}
]


var employee_history = [
{emp_id: 1, company: "ABC", Years: 4},
{emp_id: 2, company: "BCD", Years: 3},
{emp_id: 3, company: "CDE", Years: 2},
{emp_id: 4, company: "DEF", Years: 1}
]

var cities_lived = [
{emp_id: 1, city: "Moscow", Years: 1},
{emp_id: 1, city: "Doha", Years: 1},
{emp_id: 2, city: "Cairo", Years: 2},
{emp_id: 2, city: "London", Years: 1},
{emp_id: 3, city: "Tunis", Years: 2},
{emp_id: 3, city: "Beijing", Years: 2},
{emp_id: 4, city: "New York", Years: 1},
{emp_id: 4, city: "Capetown", Years: 1}
]


var cities_lived_obj = cities_lived.reduce(function(o,i){
   if(!o.hasOwnProperty(i.emp_id)){
       o[i.emp_id] = [];
   }
   o[i.emp_id].push(i);
   return o;
},{});

var employee_history_obj = employee_history.reduce(function(o,i){

   if(!o.hasOwnProperty(i.emp_id)){
       o[i.emp_id] = [];
   }
   o[i.emp_id].push(i);
   return o;
},{});

employees.forEach(function(emp){
  emp['cities'] = cities_lived_obj[emp.emp_id];
  emp['history'] = employee_history_obj[emp.emp_id];
});

console.log(employees);

JsFiddle demo - https://jsfiddle.net/f3bh0eop/2/

Upvotes: 1

Related Questions