graphql filtering on nested fields

turns out there is a limitation on graphql when filtering by nested filed, this is the details:

https://github.com/Netflix/dgs-framework/discussions/560#discussioncomment-2734401

I think this is a valid use case. If this feature is implemented, it could help a lot developers.

Our similar use case here:

type Query {
  position: [Position]
}

type Position{
  date: String
  hierarchyId: String
  securityName: String
   ...
  hierarchy: Hierarchy
}

type Hierarchy{
  portfolio: String
  book: String
  ...
}
image when a user query the data, the user could only interested in his/her only positions, something like

{
 position (date: String, portfolio: String){
   date
   securityName
   hierarchy{
     portfolio
     book
   }
 }
}
I guess ultimately, it's how the backend is handling the relationship (edges). At the moment, dgs/graphql-java is behaving like left-outer-join (in RDBMS terms), but really there should be an option for user to pick inner-join instead. I think that's the feature missing here.

I guess something like

@DgsData(parentType="Position", field="hierarchy", `join=InnerJoin`)
public Completable<Future<Hierarchy>> batchloadHierarchy(DataFetchingEnvironment dfe){
   //only return the hierarchy belong to the portfolio
}
then when dgs/graphql-jar stitching the position and hierarchy data, if it's InnerJoin, it should drop the position without hierarchy.

as a workaround, without above feature, this could be achieved through preloading.

https://netflix.github.io/dgs/advanced/context-passing/#pre-loading

something like

@DgsQuery
public DataFetcherResult<List<Position>> positions(@InputArgument..., @InputArgument portfolio, DataFetchingEnvironment dfe){
    Position position = ...//load positions
    Map<String, Hierarchy> ids  = new ConcurrentHashMap();
    if(dfe.getSelectionSet().contains("hierarchy"){
        List<Hierachy> hierarchies=...//load hierarchies
        hierarchies.parallelStream()
          .filter(s -> portfolio == null || portfolio.equalsIgnoreCase(s.getPortfolio))
         .forEach(s -> ids.putIfAbsent(s.getId(), s);
    }

   List<Postion> data = position.
     ...//filter by input arguments and ids

   return DataFectcherResult.<List<Position>>newResult()
     .data(data)
    .localContext(ids).build();
}


@DgsData(parentType="position", field="hierarchy")
public Hierarchy preloadHierarchy(DataFetchingEnvironment dfe){
   Position p = dfe.getSource();
   Map<String, Hierarchy> ids = dfe.getLocalContext();
  returns ids.get(position.getHierarchyId());
}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s