Let's assume a type hierarchy of Customer -(hasMany)-> Orders -(hasMany)-> OrderLines
Something like this:
Customer {
    Name
    Orders [
        {
            OrderId
            Date
            OrderLines [
                { 
                    ItemCount
                    ItemName
                }
            ]
        }
    ]
}
I want to query for this whole tree, and filter on properties at any level in the tree.
For instance: Get all customers who ordered 'gizmos'.
This is what I tried: at each level of the hierarchy, I specify optional arguments that would filter based on the properties available at that level:
Customer (Name) {
    Name
    Orders (OrderId, Date) [
        {
            OrderId
            Date
            OrderLines (ItemCount, ItemName) [
                { 
                    ItemCount
                    ItemName
                }
            ]
        }
    ]
}
GraphQL needs me to define how to resolve each type in the hierarchy, so when resolving, I filter based on the arguments in the query.
But what if I only specify a filter at a deep level? e.g. ItemName : 'gizmo'
Assuming there's only one order line in the system containing a gizmo, I would expect to get a response like this:
[{
    Name: "cust12",
    Orders [{
        OrderId: "ade32f",
        OrderLines: [{
            ItemCount: 50000, //customer really likes gizmos
            ItemName: "gizmo"
        }]
    }]
}]
But what I actually get is all customers (no filter there), all their orders (no filter there) and all order items, mostly empty (the items inside are filtered).
[{
    Name: "cust12",
    Orders [
    {
        OrderId: "aaaaaa",
        OrderLines: [ ]
    },
    {
        OrderId: "ade32f",
        OrderLines: [{
            ItemCount: 50000,
            ItemName: "gizmo"
        }]
    },
    {
        OrderId: "bbbbbb",
        OrderLines: [ ]
    },
    {
        OrderId: "cccccc",
        OrderLines: [ ]
    }
    ]
},
{
    Name: "cust345",
    Orders [
    {
        OrderId: "eeeeee",
        OrderLines: [ ]
    },
    {
        OrderId: "ffffff",
        OrderLines: [ ]
    }
    ]
}]
GraphQL calls the resolvers top-down: - get all (filtered) clients - for each of these get all (filtered) orders - for each of those get all (filtered) order lines
Because of the top-down nature of calling the resolvers, I get a lot more data than I bargained for.
How should I approach this?
This is actually a more complex topic than it first seems. The problem is that your current filter condition expresses
get all customers, but only include items named 'gizmo'
but what you really want is
get all customers that are related to at least one item named 'gizmo'
An elegant solution for this problem is the addition of relation filters to the schema. In your case, it could look like this:
query {
  Customer(filter: {
    orders_some: {
      orderLines_some: {
        item: {
          itemName: "gizmo"
        }
      }
    }
  }) {
    Name
    Orders {
      OrderId
      Date
      OrderLines { 
        ItemCount
        ItemName
      }
    }
  }
}
Using
orders_some: {
  orderLines_some: {
    item: {
      itemName: "gizmo"
    }
  }
}
we only fetch customers that are indirectly related to an item named 'gizmo', exactly what we wanted.
Two more examples:
query {
  Customer(filter: {
    orders_none: {
      orderLines_some: {
        item: {
          itemName: "gizmo"
        }
      }
    }
  }) {
    Name
    Orders {
      OrderId
      Date
      OrderLines { 
        ItemCount
        ItemName
      }
    }
  }
}
query {
  Customer(filter: {
    orders_every: {
      orderLines_some: {
        item: {
          itemName: "gizmo"
        }
      }
    }
  }) {
    Name
    Orders {
      OrderId
      Date
      OrderLines { 
        ItemCount
        ItemName
      }
    }
  }
}
The every, some and none relation filters are an essential part of the Graphcool APIs - you can read more here. 
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With