如何为 GraphQL 服务器设计以下解析器?

Posted

技术标签:

【中文标题】如何为 GraphQL 服务器设计以下解析器?【英文标题】:How to design the following resolver for GraphQL server? 【发布时间】:2017-05-16 23:57:17 【问题描述】:

我在meteor上使用react-apollo和mysql和sequelize,我仍然是JS的初学者。 假设我的阿波罗服务器上有以下解析器功能:

 export default resolvers = 
     Query: 
         posts(_, args)
             return Post.findAndCountAll( where: args   );
         ,
         numberOfPosts()
             return /// the number of selected posts
         
     

我想从满足某些条件的数据库中选择一些数据,然后计算所选行的数量并在“numberOfPosts”字段中返回它们。 findAndCountAll() 返回一个对象,其中包含选定的行和计数。我想让我的 post() 只返回选定的行,而我的 numberOfPosts() 只返回选定帖子的计数。现在,两者都由 posts() 返回。

我的架构是:

 type Post 
  id: Int
  date: Float
  text: String


 type NumberOfPosts
  total: Int
  filtered: Int


type Query 
  posts(
   id: Ind,
   offset: Int,
   limit: Int,
   filter: String): [Post]
  numberOfPosts:[NumberOfPosts] 


schema 
  query: Query

目标是接收以下格式的数据:


  "data": 
    "numberOfPosts": [
      
        "total": 1000,
        "filtered": 21
      
    ],
    "posts": [
      
        "id": 4,
        "date": 5105626122,
        "text": "jzybiwutudi"
      ,
      ...
    ]
  

到目前为止我的工作: 尝试 1:

  let selectedCount;
export default resolvers = 
    Query: 
        posts(_, args)
            return Post.findAndCountAll(where: args).then(
                function (results) 
                    selectedCount = results.count;
                    return results.rows
                );
        ,
        numberOfPosts()
            return selectedCount
        
    

所以我在解析器之外定义了一个帮助变量,并将其设置为选定的行数,然后在numberOfPosts() 中返回计数,这可行,但问题是return results.rows 导致错误,我不明白为什么。

另一个问题是,selectedCount 始终是之前的行数

试试 2

另一个似乎可行的解决方案是将参数两次传递到 GraphQL 查询中,如下所示:


  numberOfPosts(filter: "example") 
    total
    filtered
  
  posts(filter: "example") 
    id
    date
    text
  

然后两个解析器函数都知道相同的参数,所以我可以选择和计算相同的帖子。但这对我来说似乎不对,因为我必须两次传递相同的 args,它们也会被传输两次......

【问题讨论】:

我对@9​​87654331@一无所知,但我强烈建议不要创建selectedCount 变量,其中一个查询会将结果分配给另一个查询 谢谢,您有什么技巧可以将结果传递给其他查询吗? 我认为这是两个独立的查询,而不是一个查询中的两个相关字段? 这些解析器方法似乎与您的架构直接对应。你能更新你的问题并发布一个例子吗?如果您的rootValue 的字段名称numberOfPosts 已经返回,那么您不需要添加此解析器。将数据库设计为始终具有包含该值的字段是否更有意义? 也许吧,但我还不知道该怎么做。我已经编辑了我的问题,请再看一遍。 【参考方案1】:

您应该更多地考虑设计以及每个查询应该做什么。这些查询不应改变数据库或全局状态。

您可以做的最好的事情是简单地定义一个新类型,包括totalfiltered,就像您在第一次尝试中所做的NumberOfPosts 一样,还有帖子列表。

所以,你的架构应该是这样的:

type Post 
  id: Int
  date: Float
  text: String


type PostList 
  total: Int
  filtered: Int
  posts: [Post]


type Query 
  posts(
    id: Ind,
    offset: Int,
    limit: Int,
    filter: String): PostList


schema 
  query: Query

你解决posts 喜欢:

posts(_, args) 
  return Post.findAndCountAll( where: args ).then(result => 
    return 
      total: 1000,
      filtered: result.count,
      posts: result.rows
    
  )

请注意我是如何将 1000 作为总数的。您无法使用findAndCountAll 获取总行数。如果需要,您可以并行运行两个不同的查询并使用Promise.all 等待它们得到解决。

posts(_, args) 
  return Promise.all([
    Post.count(),
    Post.findAndCountAll( where: args )
  ]).then(data => 
    return 
      total: data[0],
      filtered: data[1].count,
      posts: data[1].rows
    
  )

上面的代码也可以从ES6's destructuring中受益:

posts(_, args) 
  return Promise.all([
    Post.count(),
    Post.findAndCountAll( where: args )
  ]).then(([totalCount, filteredData]) => 
    return 
      total: totalCount,
      filtered: filteredData.count,
      posts: filteredData.rows
    
  )

现在你可以运行了:

query 
  posts(filter:"example") 
    total
    filtered
    posts 
      id
      date
      text
    
  

然后得到:


  "data": 
    "posts": 
      "total": 1000,
      "filtered": 21,
      "posts": [
        
          "id": 4,
          "date": 5105626122,
          "text": "jzybiwutudi"
        ,
        ...
      ]
    
  

【讨论】:

谢谢,很好的回答。我想补充一点 Post.findAndCountAll 已经返回了行数,因此可以简单地使用 filtersData.count 代替 filtersData.rows.length。 哦,我也打算这样做。更新答案以供将来参考:) 我很高兴它有所帮助。 顺便说一句。这和你的解决方案一样吗?:posts(_, args) return Post.findAndCountAll( where: args ).then(data => return total: Post.count(), filtered: data [1].count, posts: data[1].rows ) 我的意思是返回会等到 Post.count() 返回值吗?还是使用 Promise.all 更安全?因为它也是这样工作的...... @henk 如果你链接这些承诺,第二个将等待第一个被首先解决。由于这两个是独立的,我们可以将它们并行化,并使用Promise.all 等待两者完成。我相信你的也可以,在这种情况下并行化它们会更好。 @henk 我相信,在您的代码中,您不需要像data[1]. 那样使用它。 data. 应该是对的。

以上是关于如何为 GraphQL 服务器设计以下解析器?的主要内容,如果未能解决你的问题,请参考以下文章

如何为 AWS 放大 GraphQL API 添加服务器端业务逻辑?

输入 graphql 解析器函数

解析器中的 AppSync GraphQL 变异服务器逻辑

Apollo GraphQL 服务器:在解析器中,从更高级别获取变量

如何为graphql查询转义变量

如何为graphql查询转义变量