【问题标题】:Graphql merge (combine) multiple queries into one?Graphql 将多个查询合并(组合)为一个?
【发布时间】:2019-07-11 15:32:24
【问题描述】:

我正在尝试使用 JavaScript 将多个 Graphql 查询组合成一个查询。
我正在寻找这样的东西:

let query3 = mergeQueries(query1, query2);

我们不会事先知道哪些查询会被合并。

假设我有这样的查询:

输入查询1:

{
  post(id: 1234) {
    title
    description
  }
}

输入查询2:

{
  post(id: 1234) {
    tags
    author {
      name
    }
  }
}

那么我希望查询结果为:
结果查询3:

{
  post(id: 1234) {
    title
    tags
    description
    author {
      name
    }
  }
}

这将与 lodash _.merge() 对 JSON 对象的功能相同,但使用 Graphql 查询而不是 JSON 对象。

【问题讨论】:

  • 您是否要尽量减少 HTTP 请求的数量?如果是的话,这可能会有所帮助blog.apollographql.com/query-batching-in-apollo-63acfd859862
  • 你不能通过简单的文本操作来做到这一点;您需要解析 GraphQL 查询并将它们连接在一起。如果存在动态类型匹配和片段,这可能会变得复杂。

标签: javascript graphql


【解决方案1】:

我的回答有点太长了,所以我决定在这里写一个直接的答案。首先,我认为这两个 cmets 都非常有帮助。有一个解决方案,让两个查询共享一个 HTTP 请求,这可能已经是您正在寻找的优化。此外,合并查询并非易事。这需要付出很多努力才能做到现场级别。不仅片段会使这变得困难,您还必须考虑变量。据我所知,没有公开的解决方案可以做到这一点,所以你必须自己做。我也没有听说过有公司这样做。我认为没有解决方案的事实表明这样做可能不值得。

我只能猜测您的问题,但减少前端应用程序发送的查询量的另一种方法是使用片段。虽然您的片段不能有变量,但健康的组件结构仍然可以很好地适应片段:

fragment PostHeader on Post {
  title
  description
}

fragment PostMeta on Post {
  tags
  author {
    name
  }
}

query {
  post(id: 1234) {
    ...PostHeader
    ...PostMeta
  }
}

【讨论】:

  • 这在很多情况下看起来是一个非常有用的解决方案。我预计输入查询之间会有很多重叠,这会使该解决方案不太理想,因此我将考虑构建自己的合并函数。
  • 我们写了一些片段组合的代码,自动命名片段和去除重复片段,在此发布:github.com/SVT/graphql-defragmentizer
【解决方案2】:

多亏了参数化片段,您可以将变量考虑在内!假设post 是根查询类型的字段,则引用上述示例的组合查询将是:

fragment PostHeader on RootQueryType {
  post(id: $id) {
    tags
    author {
      name
    }
  }
}

fragment PostMeta on RootQueryType {
  post(id: $id) {
    tags
    author {
      name
    }
  }
}

# ID being the id type
query(id: ID! = 1234) {
  ...PostHeader
  ...PostMeta
}

或者更确切地说,在实际场景中,您将动态传递 id(例如在您的发布请求中),请参阅:https://graphql.org/learn/queries/#variables

【讨论】:

    【解决方案3】:

    我为此写了一个库:https://github.com/domasx2/graphql-combine-query

    import comineQuery from 'graphql-combine-query'
    
    import gql from 'graphql-tag'
    
    const fooQuery = gql`
      query FooQuery($foo: String!) {
        getFoo(foo: $foo)
      }
    `
    
    const barQuery = gql`
      query BarQuery($bar: String!) {
        getBar(bar: $bar)
      }
    `
    
    const { document, variables } = combineQuery('FooBarQuery')
      .add(fooQuery, { foo: 'some value' })
      .add(barQuery, { bar: 'another value' })
    
    console.log(variables)
    // { foo: 'some value', bar: 'another value' }
    
    print(document)
    /*
    query FooBarQuery($foo: String!, $bar: String!) {
       getFoo(foo: $foo)
       getBar(bar: $bar)
    }
    */
    
    

    【讨论】:

    • 这看起来很有希望,但它真的很新鲜并且有错误。其中最重要的是 package.json 中的包名拼写错误。
    • @ivanjonas,除了包名,还有什么错误?
    • @DomasLapinskas 这是否也将网络调用限制为一个?
    猜你喜欢
    • 1970-01-01
    • 2012-07-09
    • 1970-01-01
    • 1970-01-01
    • 2016-02-05
    • 2018-07-29
    • 1970-01-01
    • 1970-01-01
    • 2016-04-02
    相关资源
    最近更新 更多