简体   繁体   中英

JavaScript: SQL-like join of two arrays

I have arrays like this:

const one = [
  {id: 1, field1: "a"},
  {id: 2, field1: "b"},
  {id: 3, field1: "c"},
  {id: 4, field1: "d"}
]

const two = [
  {id: 4, field2: "4"},
  {id: 1, field2: "1"}
]
// what I want to achieve:
const result = [
  {id: 1, field1: "a", field2: "1"},
  {id: 4, field1: "d", field2: "4"}
]

I want to merge one and two, so I get the result. This is very similar to a SQL join, but I want to do all of this in JavaScript code. Notice:

  1. This is "joining" by the id "column."
  2. The order of the result is the order of the one array (sorting by ID is only coincidentally the same order)
  3. Fields from both arrays exist on the result

I've figured out how to do this on my own, but the code is clunky and difficult to read. Basically, you filter over one and remove elements that don't exist in two , then you map over one and merge the fields of the two array.

Is there a more concise way of achieving this? I'm using lodash, and I was hoping there was a function in there to make this easier, but I haven't found any.

Create a dictionary or Map of the 2nd array by the key ( id ), and then filter the 1st array, and keep only items that appear in the dictionary. Afterwards, map the remaining items, and add the relevant items from the dictionary.

 const joinBy = (arr1, arr2, key) => { const arr2Dict = _.keyBy(arr2, key) return arr1 .filter(item => item[key] in arr2Dict) .map(item => ({ ...item, ...arr2Dict[item[key]] })) } const one = [{id: 1, field1: "a"},{id: 2, field1: "b"},{id: 3, field1: "c"},{id: 4, field1: "d"}] const two = [{id: 4, field2: "4"},{id: 1, field2: "1"}]; const result = joinBy(one, two, 'id') console.log(result)
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js" integrity="sha512-90vH1Z83AJY9DmlWa8WkjkV79yfS2n2Oxhsi2dZbIv0nC4E6m5AbH8Nh156kkM7JePmqD6tcZsfad1ueoaovww==" crossorigin="anonymous"></script>

If you don't want to use lodash, you can easily replace _.keyBy() , and create an object using Array.reduce() or create a Map with Array.map() .

 const joinBy = (arr1, arr2, key) => { const arr2Dict = new Map(arr2.map(o => [o[key], o])) return arr1 .filter(item => arr2Dict.has(item[key])) .map(item => ({ ...item, ...arr2Dict.get(item[key]) })) } const one = [{id: 1, field1: "a"},{id: 2, field1: "b"},{id: 3, field1: "c"},{id: 4, field1: "d"}] const two = [{id: 4, field2: "4"},{id: 1, field2: "1"}]; const result = joinBy(one, two, 'id') console.log(result)
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js" integrity="sha512-90vH1Z83AJY9DmlWa8WkjkV79yfS2n2Oxhsi2dZbIv0nC4E6m5AbH8Nh156kkM7JePmqD6tcZsfad1ueoaovww==" crossorigin="anonymous"></script>

You can use merge , map and find functions from lodash . For sorting - sortBy .

_.sortBy(
   _.map(two, (n) => _.merge(n, _.find(one, ['id', n.id]))),
   (o) => _.findIndex(one, ['id', o.id]),
);

 const one = [{id: 1, field1: "a"},{id: 2, field1: "b"},{id: 3, field1: "c"},{id: 4, field1: "d"}], two = [{id: 4, field2: "4"},{id: 1, field2: "1"}]; const r = _.sortBy( _.map(two, (n) => _.merge(n, _.find(one, ['id', n.id]))), (o) => _.findIndex(one, ['id', o.id]), ); console.log(r);
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"></script>

If you have different fields, you could take an object with the reference to the items and map two and sort by id .

 const one = [{ id: 1, field1: "a" }, { id: 2, field1: "b" }, { id: 3, field1: "c" }, { id: 4, field1: "d" }], two = [{ id: 4, field2: "4" }, { id: 1, field2: "1" }], fromOne = Object.fromEntries(one.map((object, index) => [object.id, { object, index }])), result = two .map(o => ({ ...fromOne[o.field2].object, ...o })) .sort((a, b) => fromOne[a.field2].index - fromOne[b.field2].index); console.log(result);
 .as-console-wrapper { max-height: 100% !important; top: 0; }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM