JavaScript-是否可以通过指定的键属性合并2个对象?在这种情况下,关键属性是authorId
。
注意:作者3和作者1没有匹配项,因此不应将其合并。
var b = [{"book": "book1", "authorId": 3},{"book": "book2", "authorId":2}];
var a = [{"authorId": 1, "author": "author1"},{"authorId": 2, "author": "author2"}];
var c = a.merge(b);
console.log(c);
期望:
[{"book": "book2", "authorId": 2, "author": "author2"}]
我试图在这里完成SQL JOIN的工作。
答案 0 :(得分:2)
map
by Object.assign
来自另一个数组中具有相同索引的项目:
var b = [{"book": "book1", "authorId": 1},{"book": "book2", "authorId":2}];
var a = [{"authorId": 1, "author": "author1"},{"authorId": 2, "author": "author2"}];
var c = a.map((aItem, i) => Object.assign({}, aItem, b[i]));
console.log(c);
如果不能指望每个要排序的数组,则可能reduce
进入由authorId
索引的对象,然后获取该对象的值(这具有O(N)
的复杂性而不是每次迭代都使用.find
(复杂度为O(N^2)
):
var a = [{"authorId": 1, "author": "author1"},{"authorId": 2, "author": "author2"}];
var b = [{"book": "book1", "authorId": 1},{"book": "book2", "authorId":2}];
const reduceByAuthor = (arr, initial = {}) => arr.reduce((a, item) => {
a[item.authorId] = Object.assign((a[item.authorId] || {}), item);
return a;
}, initial);
const indexedByAuthor = reduceByAuthor(a);
reduceByAuthor(b, indexedByAuthor);
console.log(Object.values(indexedByAuthor));
如果您还不能指望另一个数组中具有匹配项的每个项目,则reduce
两次,第二个reduce
仅在以下情况下分配给累加器:在第一个索引对象中找到匹配项(之后比filtering
快):
var b = [{"book": "book1", "authorId": 3},{"book": "book2", "authorId":2}];
var a = [{"authorId": 1, "author": "author1"},{"authorId": 2, "author": "author2"}];
const aIndexed = a.reduce((a, item) => {
a[item.authorId] = item;
return a;
}, {});
const c = Object.values(b.reduce((a, bItem) => {
const { authorId } = bItem;
const aItem = aIndexed[authorId];
if (aItem) a[authorId] = Object.assign({}, aItem, bItem);
return a;
}, {}))
console.log(c);
答案 1 :(得分:1)
假设您需要指定要连接的字段(因为您提到了类似SQL的语法),而不必过于担心性能(如果这样,那么您将需要为要合并的对象建立索引,但请阅读然后,您可以使用几个数组方法和一个解构分配来合并对象数组。
const b = [{"book": "book1", "authorId": 3},{"book": "book2", "authorId":2}];
const a = [{"authorId": 1, "author": "author1"},{"authorId": 2, "author": "author2"}];
// Using reduce will allow filtering of unmatched records
const merge = (field, x, z) => x.reduce((out, v) => {
// Make sure the field exists in the object to merge
// Using find will return the first object that matches the criteria (multiple record matching was not mentioned as a concern in the OP)
const match = v.hasOwnProperty(field) && z.find((c) => c[field] === v[field]);
if (match) {
// Only push onto the output array if there is a match
// Use destructuring assignment to merge the matching objects
out.push({...v, ...match});
}
return out;
}, []);
console.log(merge('authorId', a, b));
性能注意事项:出于多种原因,请谨慎使用索引方法。例如,当要合并的键的对象与要合并的数据集相比很小时。建立索引可能需要更长的时间,然后才在数组中搜索相对较少的匹配项。您应该在合理的情况下使用它们,但要注意,这样做不是一个简单的声明。
为完整起见,下面是带有临时索引的相同代码:
const b = [{"book": "book1", "authorId": 3},{"book": "book2", "authorId":2}];
const a = [{"authorId": 1, "author": "author1"},{"authorId": 2, "author": "author2"}];
const merge = (field, x, z) => {
const index = z.reduce((out, v) => {
if (v.hasOwnProperty(field)) {
out[v[field]] = v;
}
return out;
}, {});
return x.reduce((out, v) => {
const match = index[v[field]];
if (match) {
out.push({...v, ...match});
}
return out;
}, []);
};
console.log(merge('authorId', a, b));
答案 2 :(得分:0)
我认为这将通过清晰的代码满足您的需求:
var c = [];
b.map(item1 => {
a.map(item2 => {
if (item1.authorId === item2.authorId) {
c.push(Object.assign(item1, item2));
}
})
});
console.log(c);