如何为 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,它们也会被传输两次......
【问题讨论】:
我对@987654331@一无所知,但我强烈建议不要创建selectedCount
变量,其中一个查询会将结果分配给另一个查询
谢谢,您有什么技巧可以将结果传递给其他查询吗?
我认为这是两个独立的查询,而不是一个查询中的两个相关字段?
这些解析器方法似乎与您的架构直接对应。你能更新你的问题并发布一个例子吗?如果您的rootValue
的字段名称numberOfPosts
已经返回,那么您不需要添加此解析器。将数据库设计为始终具有包含该值的字段是否更有意义?
也许吧,但我还不知道该怎么做。我已经编辑了我的问题,请再看一遍。
【参考方案1】:
您应该更多地考虑设计以及每个查询应该做什么。这些查询不应改变数据库或全局状态。
您可以做的最好的事情是简单地定义一个新类型,包括total
和filtered
,就像您在第一次尝试中所做的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 添加服务器端业务逻辑?