jp1
jp1

Reputation: 57

How to "inner join" two arrays by a key in javascript?

I have two arrays containing objects like so:

const array1 = 
[
{
    "id": 1,
    "mass": 149,
    "height": 180,
    "dob": "2003-09-04"
},
{
    "id": 2,
    "mass": 140,
    "height": 175,
    "dob": "2000-02-12",
},
{
    "id": 3,
    "mass": 143,
    "height": 170,
    "dob": "2001-11-04" 
}
]

const array2 = 
[
{
    "id": 1,
    "name": "James",
    "sport": "Football"
},
{
    "id": 2,
    "name": "Adam",
    "sport": "Tennis"
}
]

I would like to merge them such that a combined array only contains data where the id appears in both array1 and array2.

So far I'm using lodash _.merge which returns:

const merged = _.merge(array1, array2)

merged = [
{
"id": 1,
"mass": 149,
"height": 180,
"dob": "2003-09-04",
"name": "James",
"sport": "Football"
},
{
"id": 2,
"mass": 140,
"height": 175,
"dob": "2000-02-12",
"name": "Adam",
"sport": "Tennis"
},
{
"id": 3,
"mass": 143,
"height": 170,
"dob": "2001-11-04" ,
}
]

I would just like merged to contain data where id appears in both, i.e:

[{
"id": 1,
"mass": 149,
"height": 180,
"dob": "2003-09-04",
"name": "James",
"sport": "Football"
},
{
"id": 2,
"mass": 140,
"height": 175,
"dob": "2000-02-12",
"name": "Adam",
"sport": "Tennis"
}]

I believe the equivalent function in something like SQL would be an "Inner join"

Any help would be greatly appreciated!

Upvotes: 2

Views: 479

Answers (3)

Dušan Stokić
Dušan Stokić

Reputation: 171

this will merge the data where the id is the same id

const merged = array2.reduce((arr, current) => {
    let array1Data = {...array1}[current.id];
    if (array1Data) {
      arr.push({...array1Data, ...current});
    }
    return arr;
}, []);

console.log(merged);

Upvotes: 0

Liftoff
Liftoff

Reputation: 25392

You can filter your first array with Array.filter to only include objects that are present in your second array before performing the same merge.

let merged = array1.filter(e => array2.some(f => f.id == e.id));

const array1 = 
[
{
    "id": 1,
    "mass": 149,
    "height": 180,
    "dob": 2003-09-04
},
{
    "id": 2,
    "mass": 140,
    "height": 175,
    "dob": 2000-02-12,
},
{
    "id": 3,
    "mass": 143,
    "height": 170,
    "dob": 2001-11-04 
}
]

const array2 = 
[
{
    "id": 1,
    "name": "James",
    "sport": "Football"
},
{
    "id": 2,
    "name": "Adam",
    "sport": "Tennis"
}
]

let merged = array1.filter(e => array2.some(f => f.id == e.id));
merged = _.merge(merged, array2);

console.log(merged);
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>

Upvotes: 1

epascarello
epascarello

Reputation: 207511

You need to map them from one to the other. Basic idea using reduce where we track the item by the id.

const array1 = [{
    "id": 1,
    "mass": 149,
    "height": 180,
    "dob": '2003-09-04'
  },
  {
    "id": 2,
    "mass": 140,
    "height": 175,
    "dob": '2000-02-12',
  },
  {
    "id": 3,
    "mass": 143,
    "height": 170,
    "dob": '2001-11-04'
  }
]

const array2 = [{
    "id": 1,
    "name": "James",
    "sport": "Football"
  },
  {
    "id": 2,
    "name": "Adam",
    "sport": "Tennis"
  }
]


const result = Object.values([...array1, ...array2].reduce((acc, userData) => {
  // have you seen the id before? If yes, use it, if no use and empty object
  const data = acc[userData.id] || {};
  //merge the objects together and store the updated data by the id
  acc[userData.id] = { ...data, ...userData };
  return acc
}, {}));

console.log(result);

Now that will include everything. If you only want the items that are in both, you can do it in two loops.

const array1 = [{
    "id": 1,
    "mass": 149,
    "height": 180,
    "dob": '2003-09-04'
  },
  {
    "id": 2,
    "mass": 140,
    "height": 175,
    "dob": '2000-02-12',
  },
  {
    "id": 3,
    "mass": 143,
    "height": 170,
    "dob": '2001-11-04'
  }
]

const array2 = [{
    "id": 1,
    "name": "James",
    "sport": "Football"
  },
  {
    "id": 2,
    "name": "Adam",
    "sport": "Tennis"
  }
]


// create a look up by the id
const array1MappedById = array1.reduce((acc, userData) => {
  acc[userData.id] = userData;
  return acc
}, {});

// Loop over the second array and make a new array with the merged data
const result = array2.reduce((arr, userData) => {
  const array1Data = array1MappedById[userData.id];
  // if the data exists in the map, then we should merge the data
  if (array1Data) {
    arr.push({...array1Data, ...userData});
  }
  return arr;
}, []);


console.log(result);

Upvotes: 2

Related Questions