JavaScript:两个数组的类SQL连接

3

我有如下的数组:

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"}
]

我想要合并one和two数组,得到结果。这与SQL join非常相似,但我想在JavaScript代码中完成所有操作。请注意:
  1. 这是通过"id"列进行"join"的。
  2. 结果的顺序是"one"数组的顺序(按ID排序只是巧合)
  3. 结果包含来自两个数组的字段
我已经自己找到了实现方法,但代码冗长且难以阅读。基本上,您需要在"one"数组上进行过滤,并删除不在"two"数组中的元素,然后在"one"数组上进行映射,合并"two"数组的字段。
有没有更简洁的方法来实现这一点?我正在使用lodash,希望能够在其中找到一个函数来使这个过程更容易,但我还没有找到任何函数。

你肯定可以用.reduce来实现这个。 - undefined
所以使用JS数据库:https://www.npmjs.com/package/database-js - undefined
1
你的答案在这里 https://dev59.com/qWMm5IYBdhLWcg3wlvwK#17504827 - undefined
为什么你有field1field2 - undefined
@Justinas 这个库很有意思,但似乎与我尝试做的事情不完全一致。如果说什么的话,它有点过于复杂了。 - undefined
@FerhatBAŞ 我认为缺少的是按照第一个数组的元素进行排序。 - undefined
3个回答

4
创建一个字典或 Map,以第二个数组的键(id)为依据,并过滤第一个数组,只保留出现在字典中的项。然后,映射剩余的项,并添加来自字典的相关项。

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>

如果您不想使用lodash,可以轻松地替换_.keyBy(),并使用Array.reduce()创建一个对象或者使用Array.map()创建一个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>


2
你可以使用来自lodashmergemapfind函数。对于排序-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>


@DanielKaplan 当然,已修复。 - undefined
看起来你是按照ID进行排序。就像我说的,这只是巧合地符合我的要求。我想要的是第一个数组的顺序。 - undefined
@DanielKaplan 你明白了。 - undefined

0
如果你有不同的字段,你可以使用一个带有对项目的引用的对象,并通过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; }


看起来你是按照ID进行排序。就像我说的,这只是巧合地符合我的要求。我想要的是第一个数组的顺序。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接