GraphQL - 如何过滤层次结构? ("customers who ordered gizmos last month")

GraphQL - how to filter a hierarchy? ("customers who ordered gizmos last month")

让我们假设类型层次结构为 Customer -(hasMany)-> Orders -(hasMany)-> OrderLines

像这样:

Customer {
    Name
    Orders [
        {
            OrderId
            Date
            OrderLines [
                { 
                    ItemCount
                    ItemName
                }
            ]
        }
    ]
}

我想查询整棵树,并对树中 任何级别 的属性进行 过滤

例如:获取所有订购了'gizmos'的客户。

这是我尝试过的方法:在层次结构的每个级别,我都指定了可选参数,这些参数将根据该级别可用的属性进行过滤:

Customer (Name) {
    Name
    Orders (OrderId, Date) [
        {
            OrderId
            Date
            OrderLines (ItemCount, ItemName) [
                { 
                    ItemCount
                    ItemName
                }
            ]
        }
    ]
}

GraphQL 需要我定义如何解析层次结构中的每个类型,因此在解析时,我根据查询中的参数进行过滤。

但是,如果我只在深层指定过滤器会怎么样?例如ItemName : 'gizmo'

假设系统中只有一个订单行包含一个 gizmo,我希望得到这样的响应:

[{
    Name: "cust12",
    Orders [{
        OrderId: "ade32f",
        OrderLines: [{
            ItemCount: 50000, //customer really likes gizmos
            ItemName: "gizmo"
        }]
    }]
}]

但我实际得到的是 所有 客户(那里没有过滤器),所有 他们的订单(那里没有过滤器)和 全部个订单商品,大部分是空的(里面的商品已过滤)。

[{
    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 调用解析器自上而下: - 获取所有(过滤的)客户 - 对于其中的每一个,获取所有(过滤的)订单 - 对于每个获取所有(过滤的)订单行

由于调用解析器的自上而下的性质,我得到的数据比我预想的要多得多。

我该如何处理?

关系过滤器

这实际上是一个比乍看起来更复杂的话题。问题是您当前的过滤条件表示

get all customers, but only include items named 'gizmo'

但你真正想要的是

get all customers that are related to at least one item named 'gizmo'

获取与至少一项名为 'gizmo'

的项目相关的所有客户

此问题的一个优雅解决方案是向模式添加关系过滤器。在您的情况下,它可能看起来像这样:

query {
  Customer(filter: {
    orders_some: {
      orderLines_some: {
        item: {
          itemName: "gizmo"
        }
      }
    }
  }) {
    Name
    Orders {
      OrderId
      Date
      OrderLines { 
        ItemCount
        ItemName
      }
    }
  }
}

使用

orders_some: {
  orderLines_some: {
    item: {
      itemName: "gizmo"
    }
  }
}

我们只获取与名为 'gizmo' 的项目间接相关的客户,这正是我们想要的。

另外两个例子:

获取与名为 'gizmo'

的任何项目无关的所有客户
query {
  Customer(filter: {
    orders_none: {
      orderLines_some: {
        item: {
          itemName: "gizmo"
        }
      }
    }
  }) {
    Name
    Orders {
      OrderId
      Date
      OrderLines { 
        ItemCount
        ItemName
      }
    }
  }
}

获取所有客户,其中他们的所有订单都包含一些订单行,其中包含一个名为 'gizmo'

的项目
query {
  Customer(filter: {
    orders_every: {
      orderLines_some: {
        item: {
          itemName: "gizmo"
        }
      }
    }
  }) {
    Name
    Orders {
      OrderId
      Date
      OrderLines { 
        ItemCount
        ItemName
      }
    }
  }
}

everysomenone 关系过滤器是 Graphcool API 的重要组成部分 - 您可以 read more here