TypeScript对象数组转指定结构及forEach循环优化需求
问题:TypeScript中按Section分类结构化API输出
我用TypeScript结合MySQL开发API,当前通过reduce和forEach循环将employerRes与getEmployerDetail按issuer_id关联,但结果是所有详情集中在单个getEmployerDetail数组里。需要优化逻辑,将详情按Section字段拆分为employmentType、professionalField等独立数组,生成目标格式的结构化输出。
当前代码
let values = employerRes.reduce((prev: any, curr: any) => ({ ...prev, [curr.issuer_id]: { issuer_id: curr.issuer_id, ...prev[curr.issuer_id], [(curr.name).replaceAll(' ', "_")]: curr[`${curr.datatype}_value`] Object.values(values).forEach((x: any) => { Object.values(getEmployerDetail).forEach((Benefit: any) => { if (x.issuer_id == Benefit.issuer_id) { Object.assign(values[id],{getEmployerDetail} ) } }) })
现有输出
[ { "issuer_id": 2639, "job_title": "Sales Manager", "hr-contact": "9767865459", "adress": "bangalore", "image": "http://localhost:3003/public/uploads/company-logos/undefined", "job_type": "top", "company_name": "Limendo", "cover_image": "http://localhost:3003/public/uploads/company-logos/undefined", "number_of_employees": null, "overview": "What is a company overview? A company overview provides the reader of your business plan with basic background information about your company so they have an understanding of what you do, who the management team is and what customers your business serves.", "getEmployerDetail": [ { "issuer_id": 2639, "Field_of_activity": "Jobs", "id": 111, "Section": "Communes", "Content": "Mühlwald", "foa_section_content_id": 111 }, { "issuer_id": 2639, "Field_of_activity": "Jobs", "id": 112, "Section": "Communes", "Content": "Wolkenstein in Gröden", "foa_section_content_id": 112 }, { "issuer_id": 2639, "Field_of_activity": "Jobs", "id": 150, "Section": "Professional field", "Content": "Marketing, Graphics, PR", "foa_section_content_id": 150 }, { "issuer_id": 2639, "Field_of_activity": "Jobs", "id": 162, "Section": "Branch", "Content": "Banks, Finance, Insurance", "foa_section_content_id": 162 }, { "issuer_id": 2639, "Field_of_activity": "Jobs", "id": 215, "Section": "Benefits", "Content": "Enrolment programme", "foa_section_content_id": 215 }, { "issuer_id": 2639, "Field_of_activity": "Jobs", "id": 220, "Section": "Benefits", "Content": "Childcare", "foa_section_content_id": 220 } ] } ]
期望输出
{ "tender_id": 8, "job_title": "React developer", "enterprise": "Limendo", "publishing_date": "2022-11-27T07:43:06.000Z", "job_description": "developer for React ", "hr-contact": "stefan@limendo.com", "adress": "bolzano/italy 5", "image": "http://20.216.184.59:3003/public/uploads/company-logos/image-1668363010612.png", "job_type": "FULL TIME", "employmentType": [ { "id": 198, "Employment_type": "Freelancer" } ], "professionalField": [ { "id": 150, "Professional_field": "Marketing, Graphics, PR" } ], "benefits": [ { "id": 215, "Benefits": "Enrolment programme" }, { "id": 219, "Benefits": "Canteen" }, { "id": 220, "Benefits": "Childcare" }, { "id": 221, "Benefits": "Employee events" }, { "id": 222, "Benefits": "Employee mobile phone" }, { "id": 223, "Benefits": "Employee notebook" }, { "id": 224, "Benefits": "Employee bonuses" } ], "branch": [ { "id": 162, "Branch": "Banks, Finance, Insurance" } ], "communes": [], "positionLevel": [], "skillSets": [], "languageSkills": [], "skillRepository": [], "jobCluster": [], "jobClusterDescription": [] }
解决方案
优化后的代码
// 1. 聚合employerRes,生成每个雇主的基础字段结构 const employerMap = employerRes.reduce((prev: Record<string, any>, curr: any) => { const existing = prev[curr.issuer_id] || { issuer_id: curr.issuer_id }; return { ...prev, [curr.issuer_id]: { ...existing, [curr.name.replaceAll(' ', "_")]: curr[`${curr.datatype}_value`] } }; }, {}); // 2. 处理getEmployerDetail,按issuer_id分组并按Section分类 const detailMap = getEmployerDetail.reduce((prev: Record<string, any>, curr: any) => { const issuerId = curr.issuer_id.toString(); // 初始化当前雇主的所有分类数组 if (!prev[issuerId]) { prev[issuerId] = { employmentType: [], professionalField: [], benefits: [], branch: [], communes: [], positionLevel: [], skillSets: [], languageSkills: [], skillRepository: [], jobCluster: [], jobClusterDescription: [] }; } // Section与目标字段的映射关系 const sectionMapping: Record<string, string> = { "Employment type": "employmentType", "Professional field": "professionalField", "Benefits": "benefits", "Branch": "branch", "Communes": "communes", "Position level": "positionLevel", "Skill sets": "skillSets", "Language skills": "languageSkills", "Skill repository": "skillRepository", "Job cluster": "jobCluster", "Job cluster description": "jobClusterDescription" }; const targetField = sectionMapping[curr.Section]; if (targetField) { // 生成符合格式的条目 const key = curr.Section.replaceAll(' ', "_"); prev[issuerId][targetField].push({ id: curr.id, [key]: curr.Content }); } return prev; }, {}); // 3. 合并基础信息和分类后的详情 const result = Object.values(employerMap).map(employer => { const issuerId = employer.issuer_id.toString(); return { ...employer, ...detailMap[issuerId] }; });
代码说明
- 基础信息聚合:用reduce把
employerRes按issuer_id分组,合并每个雇主的字段,避免重复处理。 - 详情分类映射:
- 先按
issuer_id分组存储详情,同时初始化所有目标分类数组(空数组保证格式统一)。 - 通过
sectionMapping将原Section值对应到输出的驼峰名字段,确保结构匹配期望格式。 - 遍历每个详情项,将
id和Content按对应格式加入目标数组。
- 先按
- 结果合并:把基础雇主信息和分类后的详情数组合并,得到最终结构化输出。
内容的提问来源于stack exchange,提问作者jaga b
相关产品推荐
相关产品推荐

