使用Javascript操作对象并合并类似的数据



我正在努力操作Javascript对象,非常感谢您的建议:

我有以下对象:

const source = {
id: '1',
name: 'Customer A',
projects: [
{
id: '10',
name: 'Project 2',
description: 'Project 2 description',
products: [
{
id: '100',
name: 'Product 1',
vendor: 'Vendor 1',
instances: [
{
id: '1000',
operatingSystem: 'Microsoft Windows 2012R2',
environment: 'Prod',
version: '4.1',
notes: '',
},
],
},
{
id: '200',
name: 'Product 2',
vendor: 'Vendor 2',
instances: [
{
id: '2000',
operatingSystem: 'Microsoft Windows 2016',
environment: 'Prod',
version: '4.0',
notes: '',
},
],
},
],
},
{
id: '20',
name: 'Project 1',
description: 'Project 1 description',
products: [
{
id: '200',
name: 'Product 2',
vendor: 'Vendor 2',
instances: [
{
id: '2000',
operatingSystem: 'Microsoft Windows 2016',
environment: 'Prod',
version: '4.0',
notes: '',
},
{
id: '3000',
operatingSystem: 'RedHat Linux 7',
environment: 'Prod',
version: '3.12',
notes: '',
},
],
},
],
},
],
};

我想从上面的对象中提取一个按产品分组的实例列表(这部分工作正常(:

const products = [
{
id: '100',
name: 'Product 1',
vendor: 'Vendor 1',
instances: [
{
id: '1000',
operatingSystem: 'Microsoft Windows 2012R2',
environment: 'Prod',
version: '4.1',
notes: '',
},
],
},
{
id: '200',
name: 'Product 2',
vendor: 'Vendor 2',
instances: [
{
id: '2000',
operatingSystem: 'Microsoft Windows 2016',
environment: 'Prod',
version: '4.0',
notes: '',
},
{
id: '2000',
operatingSystem: 'Microsoft Windows 2016',
environment: 'Prod',
version: '4.0',
notes: '',
},
{
id: '3000',
operatingSystem: 'RedHat Linux 7',
environment: 'Prod',
version: '3.12',
notes: '',
},
],
},
];

以上是通过映射项目、扁平化产品阵列和减少结果来实现的。我的下一个目标是为每个实例添加与其关联的项目。我需要附加项目id和项目名称。在上面的示例中,您可以看到id为"2000"的实例与2个项目相关联,因此,预期结果应该如下所示:

const expected = [
{
id: '100',
name: 'Product 1',
vendor: 'Vendor 1',
instances: [
{
id: '1000',
operatingSystem: 'Microsoft Windows 2012R2',
environment: 'Prod',
version: '4.1',
notes: '',
projects: [
{
id: '10',
name: 'Project 2',
},
],
},
],
},
{
id: '200',
name: 'Product 2',
vendor: 'Vendor 2',
instances: [
{
id: '2000',
operatingSystem: 'Microsoft Windows 2016',
environment: 'Prod',
version: '4.0',
notes: '',
projects: [
{
id: '10',
name: 'Project 2',
},
{
id: '20',
name: 'Project 1',
},
],
},
{
id: '3000',
operatingSystem: 'RedHat Linux 7',
environment: 'Prod',
version: '3.12',
notes: '',
projects: [
{
id: '20',
name: 'Project 1',
},
],
},
],
},
];

我试图通过几个"forEach"循环、映射等操作数组,但没有成功。如果您能就如何实现这一目标提出自己的想法,我将不胜感激。

const { inspect } = require('util'); // if Node.js
const source = {
id: '1', name: 'Customer A', projects: [
{
id: '10', name: 'Project 2', description: 'Project 2 description', products: [
{
id: '100', name: 'Product 1', vendor: 'Vendor 1', instances: [
{ id: '1000', operatingSystem: 'Microsoft Windows 2012R2', environment: 'Prod', version: '4.1', notes: '', },
],
},
{
id: '200', name: 'Product 2', vendor: 'Vendor 2', instances: [
{ id: '2000', operatingSystem: 'Microsoft Windows 2016', environment: 'Prod', version: '4.0', notes: '', },
],
},
],
},
{
id: '20', name: 'Project 1', description: 'Project 1 description', products: [
{
id: '200', name: 'Product 2', vendor: 'Vendor 2', instances: [
{ id: '2000', operatingSystem: 'Microsoft Windows 2016', environment: 'Prod', version: '4.0', notes: '', },
{ id: '3000', operatingSystem: 'RedHat Linux 7', environment: 'Prod', version: '3.12', notes: '', },
],
},
],
},
],
};
const projectToIdMap = source.projects.reduce((projectToIdMap, { name, products }) => {
projectToIdMap[name] = [];
products.forEach(({ instances }) => {
instances.forEach(({ id }) => {
projectToIdMap[name].push(id);
});
});
return projectToIdMap;
}, {});
const products = [
{
id: '100', name: 'Product 1', vendor: 'Vendor 1', instances: [
{ id: '1000', operatingSystem: 'Microsoft Windows 2012R2', environment: 'Prod', version: '4.1', notes: '', },
],
},
{
id: '200', name: 'Product 2', vendor: 'Vendor 2', instances: [
{ id: '2000', operatingSystem: 'Microsoft Windows 2016', environment: 'Prod', version: '4.0', notes: '', },
{ id: '2000', operatingSystem: 'Microsoft Windows 2016', environment: 'Prod', version: '4.0', notes: '', },
{ id: '3000', operatingSystem: 'RedHat Linux 7', environment: 'Prod', version: '3.12', notes: '', },
],
},
];
products.forEach(({ instances }) => {
instances.forEach(instance => {
instance.projects = [];
const { id } = instance;
Object.entries(projectToIdMap).forEach(([project, os], i) => {
if (projectToIdMap[project].includes(id)) {
instance.projects.push({ id: (i + 1) * 10, project });
}
});
});
});
console.log(inspect(products, false, null, true)); // if Node.js

这不会删除重复的Microsoft Windows 2016条目,但我相信您可以从这里删除它。

好吧,我想我做到了:(

感谢@GirkovArpa的帮助!

您可以在代码片段或原始问题中找到源对象。

预期对象是:

const expected = [
{
id: '100',
name: 'Product 1',
vendor: 'Vendor 1',
instances: [
{
id: '1000',
operatingSystem: 'Microsoft Windows 2012R2',
environment: 'Prod',
version: '4.1',
notes: '',
projects: [
{
id: '10',
name: 'Project 2',
},
],
},
],
},
{
id: '200',
name: 'Product 2',
vendor: 'Vendor 2',
instances: [
{
id: '2000',
operatingSystem: 'Microsoft Windows 2016',
environment: 'Prod',
version: '4.0',
notes: '',
projects: [
{
id: '10',
name: 'Project 2',
},
{
id: '20',
name: 'Project 1',
},
],
},
{
id: '3000',
operatingSystem: 'RedHat Linux 7',
environment: 'Prod',
version: '3.12',
notes: '',
projects: [
{
id: '20',
name: 'Project 1',
},
],
},
],
},
];

首先,我以数组的形式添加了每个实例的项目

然后我将产品数组结果压平,这样它就不会被拆分为对象

然后我使用了来自以下线程的@Yevgen-Gorbunkov帮助:合并对象数组中的重复项,插入嵌套数组

我改变了他的功能,在合并相关项目时也删除了重复的产品(这就是为什么我首先用数组初始化项目字段(

如果你会找到一个更好或更有效的wat来改进方法-我很乐意听到:(

编辑

我更改了的代码片段

dupe.instances = { ...o.instances };

dupe.instances = Object.values({ ...o.instances });

用于将实例添加为数组而不是对象。

/* Source object */
const source = {
id: '1', name: 'Customer A', projects: [
{
id: '10', name: 'Project 2', description: 'Project 2 description', products: [
{
id: '100', name: 'Product 1', vendor: 'Vendor 1', instances: [
{ id: '1000', operatingSystem: 'Microsoft Windows 2012R2', environment: 'Prod', version: '4.1', notes: '', },
],
},
{
id: '200', name: 'Product 2', vendor: 'Vendor 2', instances: [
{ id: '2000', operatingSystem: 'Microsoft Windows 2016', environment: 'Prod', version: '4.0', notes: '', },
],
},
],
},
{
id: '20', name: 'Project 1', description: 'Project 1 description', products: [
{
id: '200', name: 'Product 2', vendor: 'Vendor 2', instances: [
{ id: '2000', operatingSystem: 'Microsoft Windows 2016', environment: 'Prod', version: '4.0', notes: '', },
{ id: '3000', operatingSystem: 'RedHat Linux 7', environment: 'Prod', version: '3.12', notes: '', },
],
},
],
},
],
};
/* flattenArray function */
function flattenArray(data) {
const initialValue = [];
return data.reduce((total, value) => {
return total.concat(Array.isArray(value) ? flattenArray(value) : value);
}, initialValue);
}
/* Adding an array of project on each instance */
source.projects.forEach(project => {
project.products.forEach(product => {
product.instances.forEach(instance => {
instance.project = [
{
id: project.id,
name: project.name
}
];
});
});
});
/* flatten the array */
let products = flattenArray(source.projects.map(p => p.products));
/* reducing products and merging id equaly instances + projects */
products = [
...products
.reduce((r, o) => {
const dupe = r.get(o.id);
if (dupe) {
const a = flattenArray(dupe.instances).reduce(i => i);
o.instances.forEach(i => {
if (i.id === a.id) {
const merged = [...i.project, ...a.project];
i.project = merged;
}
});
dupe.instances = Object.values({ ...o.instances });
} else {
r.set(o.id, o);
}
return r;
}, new Map())
.values()
];
console.log("products", products);

最新更新