如何优化Angular+NestJS+GraphQL+MongoDB多字段过滤函数?
多字段过滤逻辑优化方案(Angular/NestJS/GraphQL/MongoDB)
我当前使用Angular、NestJS、GraphQL和MongoDB技术栈开发,现有一个多字段数据过滤模态组件,原有的过滤代码存在大量冗余条件判断,希望优化为更整洁的实现。
原冗余代码示例
let matchingValue: any; let matchingValuePipeline: any; // const { bySn, byBank, byClient, byModel, byRegion, bySite, byTerminalId } = // search; for (let item in search) { if (search[item] === '') { matchingValue = { inUse: true }; matchingValuePipeline = { bindedSuperAdmin: name }; } } //----------------------------- if (search.byBank) { matchingValuePipeline = { bindedBanque: search.byBank }; } if (search.byBank && search.byClient) { matchingValuePipeline = { bindedBanque: search.byBank, bindedClient: search.byClient, }; } if (search.byBank && search.byClient && search.bySite) { matchingValuePipeline = { bindedBanque: search.byBank, bindedClient: search.byClient, nameUser: search.bySite, }; } if (search.byBank && search.byClient && search.bySite && search.byModel) { matchingValuePipeline = { bindedBanque: search.byBank, bindedClient: search.byClient, nameUser: search.bySite, }; matchingValue = { inUse: true, model: search.byModel }; } if ( search.byBank && search.byClient && search.bySite && search.byModel && search.byRegion ) { matchingValuePipeline = { bindedBanque: search.byBank, bindedClient: search.byClient, nameUser: search.bySite, region: search.byRegion, }; matchingValue = { inUse: true, model: search.byModel }; } if ( search.byBank && search.byClient && search.bySite && search.byModel && search.byRegion && search.bySn ) { matchingValuePipeline = { bindedBanque: search.byBank, bindedClient: search.byClient, nameUser: search.bySite, region: search.byRegion, }; matchingValue = { inUse: true, model: search.byModel, sn: search.bySn }; } if ( search.byBank && search.byClient && search.bySite && search.byModel && search.byRegion && search.bySn && search.byTerminalId ) { matchingValuePipeline = { bindedBanque: search.byBank, bindedClient: search.byClient, nameUser: search.bySite, region: search.byRegion, }; matchingValue = { inUse: true, model: search.byModel, sn: search.bySn, terminalId: search.byTerminalId, }; } if (search.byClient) { matchingValuePipeline = { bindedClient: search.byClient }; } if (search.bySite) { matchingValuePipeline = { nameUser: search.bySite }; } if (search.byRegion) { matchingValuePipeline = { region: search.byRegion }; } if (search.bySn) { matchingValue = { sn: search.bySn }; } if (search.byModel) { matchingValue = { model: search.byModel }; } if (search.byTerminalId) { matchingValue = { terminalId: search.byTerminalId }; } //-------------------------------------- // for testing purpose console.log('matchingValue', matchingValue); console.log('matchingValuePipeline', matchingValuePipeline); console.log('search', search); let filter; if (role === ROLEV1.MS_TECH_SOFT) { filter = await this.modelTpe.aggregate([ { $match: matchingValue, }, { $lookup: { from: 'profiles', localField: 'merchantName', foreignField: 'nameUser', as: 'listTpe', pipeline: [ { $match: matchingValuePipeline, }, ], }, },
对应的SearchMethods DTO:
@InputType() export class SearchMethods { @Field({ nullable: true }) bindedBanque?: string; @Field({ nullable: true }) bindedClient?: string; @Field({ nullable: true }) nameUser?: string; @Field({ nullable: true }) region?: string; @Field({ nullable: true }) model?: string; @Field({ nullable: true }) sn: string; @Field({ nullable: true }) terminalId?: string; }
优化后的实现方案
核心逻辑代码
// 定义前端搜索参数到MongoDB字段的映射关系 const pipelineFieldMap = { byBank: 'bindedBanque', byClient: 'bindedClient', bySite: 'nameUser', byRegion: 'region', }; const valueFieldMap = { bySn: 'sn', byModel: 'model', byTerminalId: 'terminalId', }; // 初始化匹配对象,设置默认条件 const matchingValue: any = { inUse: true }; const matchingValuePipeline: any = { bindedSuperAdmin: name }; // 处理空值情况:如果有任何搜索字段为空,保留默认条件(可根据需求调整) const hasEmptyField = Object.values(search).some(val => val === ''); if (!hasEmptyField) { // 动态构建matchingValuePipeline Object.entries(pipelineFieldMap).forEach(([searchKey, dbField]) => { if (search[searchKey]) { matchingValuePipeline[dbField] = search[searchKey]; } }); // 动态构建matchingValue Object.entries(valueFieldMap).forEach(([searchKey, dbField]) => { if (search[searchKey]) { matchingValue[dbField] = search[searchKey]; } }); } // 测试输出 console.log('matchingValue', matchingValue); console.log('matchingValuePipeline', matchingValuePipeline); console.log('search', search); // 集成到聚合查询 let filter; if (role === ROLEV1.MS_TECH_SOFT) { filter = await this.modelTpe.aggregate([ { $match: matchingValue }, { $lookup: { from: 'profiles', localField: 'merchantName', foreignField: 'nameUser', as: 'listTpe', pipeline: [{ $match: matchingValuePipeline }], }, }, // 其他聚合阶段... ]); }
优化点说明
- 字段映射配置:用
pipelineFieldMap和valueFieldMap统一管理前端参数与数据库字段的对应关系,后续新增/修改字段只需调整映射表,无需修改业务逻辑 - 动态条件构建:通过遍历映射表自动添加非空条件,彻底消除多层嵌套的if判断
- 默认条件统一处理:初始化时直接设置
inUse: true和bindedSuperAdmin的默认值,空值场景单独判断后保留默认逻辑 - 代码简洁可维护:原100+行的条件判断压缩到30行以内,逻辑清晰,降低后续维护成本
内容的提问来源于stack exchange,提问作者maryem w
相关产品推荐
相关产品推荐

