如何为GraphQL查询添加过滤参数至Schema及Resolver
支持复杂过滤的GraphQL Schema实现
需要实现对应以下GraphQL查询的Schema,支持limit、嵌套or/and的where过滤条件,并在Resolver中解析参数传入voyageAristowService.getVoyageData()完成MongoDB数据过滤:
query ($DateFilter: Date!, $oType: String, $voyStat: VoyageVoyageStatusCodeEnum) { imos { voyageList (query: { limit: 1 where: { or : [ {lastUpdateGmt: {isAfter : $DateFilter}}, {completeDateGmt: {isAfter : $DateFilter}} ] and : [ {oprType: {is : $oType }}, {voyageStatusCode: {isNot : $voyStat }} ] } }) { vesselCode lastUpdateGmt voyageNo voyageStatus tradeAreaName oprType completeDateGmt commenceDateGmt vessel { vesselType isActive } } } }
原Schema存在的问题
- 未定义查询中使用的
VoyageVoyageStatusCodeEnum枚举类型 - 输入类型的字段强制非空(如
DateFilterInput.isAfter: Date!),不符合查询中可选参数的场景 - 单独定义的过滤输入类型(
DateFilterInput、OprTypeInput)扩展性差 - Resolver未处理嵌套
or/and条件到MongoDB查询语法的转换
修正后的Schema
#graphql scalar Date # 定义查询中用到的枚举类型,需补充实际业务枚举值 enum VoyageVoyageStatusCodeEnum { IN_PROGRESS COMPLETED CANCELLED } # 通用比较输入类型,覆盖is、isNot、isAfter等操作 input ComparisonInput { is: String isNot: String isAfter: Date } # 嵌套过滤条件输入,支持or/and组合 input VoyageWhereInput { or: [VoyageWhereInput!] and: [VoyageWhereInput!] lastUpdateGmt: ComparisonInput completeDateGmt: ComparisonInput oprType: ComparisonInput voyageStatusCode: ComparisonInput } # 查询参数输入,limit和where均设为可选 input VoyageQueryInput { limit: Int where: VoyageWhereInput } type AristowVessel { vesselType: String isActive: Boolean } type VoyageAristow { vesselCode: String lastUpdateGmt: String voyageNo: Int voyageStatus: String oprType: String tradeAreaName: String commenceDateGmt: Date completeDateGmt: Date vessel: AristowVessel } type VoyageAristowList { voyageList(query: VoyageQueryInput): [VoyageAristow] } type Query { imos: VoyageAristowList }
Resolver实现示例(JavaScript)
const resolvers = { Query: { imos: () => ({}) }, VoyageAristowList: { async voyageList(parent, { query }, context) { // 转换GraphQL过滤条件为MongoDB查询语法 const mongoQuery = convertToMongoQuery(query?.where || {}); // 设置默认limit值 const limit = query?.limit || 10; // 调用服务层方法传入参数 return await context.voyageAristowService.getVoyageData({ query: mongoQuery, limit }); } } }; // 递归转换嵌套的or/and条件到MongoDB语法 function convertToMongoQuery(whereInput) { const mongoQuery = {}; // 处理or条件 if (whereInput.or) { mongoQuery.$or = whereInput.or.map(convertToMongoQuery); } // 处理and条件 if (whereInput.and) { mongoQuery.$and = whereInput.and.map(convertToMongoQuery); } // 处理字段级比较条件 Object.keys(whereInput).forEach(key => { if (key === 'or' || key === 'and') return; const comparison = whereInput[key]; const fieldQuery = {}; if (comparison.is) fieldQuery.$eq = comparison.is; if (comparison.isNot) fieldQuery.$ne = comparison.isNot; if (comparison.isAfter) fieldQuery.$gt = comparison.isAfter; if (Object.keys(fieldQuery).length > 0) { mongoQuery[key] = fieldQuery; } }); return mongoQuery; }
关键说明
- 通用
ComparisonInput避免重复定义字段输入类型,提升扩展性 - 递归处理
or/and嵌套条件,将GraphQL过滤结构转换为MongoDB的$or/$and查询语法 - 所有输入字段设为可选,匹配查询中参数可选的场景
- 补充缺失的枚举类型,需根据实际业务值填充枚举成员
内容的提问来源于stack exchange,提问作者Himanshu Kumar
相关产品推荐
相关产品推荐

