GraphQL基于子级保单状态过滤父级客户数据的冗余问题求解
问题背景
客户名下存在多个保单,需根据保单状态筛选符合条件的客户。现有GraphQL schema定义如下:
customersByPolicyStatusCriteria( status: [String!]! ): CustomerSearchResult! type CustomerSearchResult { dataset: [Customer] } type Customer { clientNumber: ID! name: CustomerName policies(status: [String]): [CustomerPolicy] }
当前存在的问题
当前实现存在操作冗余问题:父级查询需先按保单状态过滤客户,子Resolver拿到父级数据后还要再次过滤保单才能得到正确结果。
示例说明:用Cx代表客户,Px代表保单状态,现有C1(P1,P2)、C2(P3,P1,P2)、C3(P3),按[P1,P2]过滤后期望返回C1(P1,P2)、C2(P1,P2)。
目前两类错误实现的结果:
- 若移除父级过滤:会返回所有客户,无符合要求保单的客户policies字段为空,示例返回结果为C1(P1,P2)、C2(P1,P2)、C3(null)
- 若移除子级过滤:返回客户的全部保单,包含不符合状态的保单,示例返回结果为C1(P1,P2)、C2(P3,P1,P2)
现有待探索方案适用性分析
你提到的三个方案适配性如下:
- 修改schema:若修改对外暴露的接口结构,需要兼容现有调用方,改造成本较高;若仅新增内部非暴露字段存储中间结果,可实现但不是最优解
- 采用GraphQL Join:仅适用于多服务联邦图谱的复杂场景,单服务场景下引入会大幅提升架构复杂度,投入产出比极低
- 在PolicyResolver触发指定条件时直接移除父级Customer节点:不符合GraphQL标准执行流程,属于hack实现,后续排查问题难度高,容易引发边界异常,不建议使用
高效解决方案
最优方案:上下文传递+父Resolver预加载匹配数据
该方案完全兼容现有schema,无冗余查询,执行效率最高,实现逻辑如下:
- 父级Resolver执行
customersByPolicyStatusCriteria查询时,一次关联查询同时拿到「所有名下存在指定状态保单的客户」,以及对应客户名下符合状态的保单列表,把预查询到的匹配保单列表存入当前Customer对象的内部临时属性(不需要在schema中定义,仅作为上下文传递,不会对外暴露) - 子级
policies字段的Resolver执行时,先做两层判断:- 当前查询是否来自
customersByPolicyStatusCriteria接口的关联查询 - 调用
policies时传入的status参数和父查询的status参数是否一致
- 当前查询是否来自
- 如果两个判断都满足,直接返回父级预加载的匹配保单列表,不需要再次查询数据库或者执行过滤逻辑;否则走原有常规查询逻辑即可
若服务已引入DataLoader组件,还可以在常规查询场景下批量合并保单查询请求,进一步降低数据库压力。
内容的提问来源于stack exchange,提问作者Paraneetharan Saravanaperumal
相关产品推荐
相关产品推荐

