我正在使用Absinthe来构建GraphQL API。数据存储区为Dgraph,它使用GraphQL +作为查询语言。它类似于GraphQL但不完全相同。
这在理论上会让我处于一个美好的境地。一个GraphQL查询,如
query {
user {
id
username
posts {
title
text
comments {
text
}
}
}
}
也可能只是Dgraph中的一个查询。它看起来几乎相同:
{
users(func: has(type_user))
{
id
username
posts {
title
text
comments {
text
}
}
}
}
图形数据库一次性加载复杂关系的能力是我想要使用的。问题只是:在Absinthe中,模式应该是可组合的。在架构中,将有一个:user
对象,其:posts
字段为list_of(:post
。然后是:post
个对象。等等。
为了帮助阻止N + 1查询,您可以使用dataloader或批量加载。
现在我可以一次性加载所有内容。例如,我可以编写一个解析器:
defmodule MyApp.Resolvers.User do
alias MyApp.Users
def users(_, _args, _) do
{:ok, Users.all()}
end
end
实际查询db的用户上下文
defmodule MyApp.Users do
alias MyApp.Users.User
def all do
query = """
{
users(func: has(type_user))
{
id
username
posts {
title
text
comments {
text
}
}
}
}
"""
case ExDgraph.query(conn(), query) do
{:ok, msg} ->
%{result: %{users: users}} = msg
Enum.map(users, fn x -> struct(User, x) end)
{:error, _error} ->
[]
end
end
end
这里的问题是我过度抓取。我总是查询所有内容,即使我只想要一个用户列表。这有效,但表现不是很好。而且我放松了可组合性。
如果我有权访问解析器中的查询以了解请求的字段,那将是什么解决方案。然后,我可以使用模式匹配来构建查询,然后将其发送到Dgraph。我甚至可以有一个中央解析器和许多查询构建器。但我需要挂钩查询并直接解析它。
这样的事情可能吗?知道在哪里可以找到有趣的东西来解决这个问题吗?也许与Absinthe中间件?
谢谢!
答案 0 :(得分:0)
我想我找到了解决方案。让我们拿一个解决方案来获取用户列表。像这样:
object :user_queries do
field :users, list_of(:user) do
resolve fn _parent, _, resolution ->
IO.inspect(resolution.definition.selections)
{:ok, Users.all()}
end
end
end
如果您使用嵌套查询点击它,请执行以下操作:
{
users {
id
name
posts {
id
title
text
comments {
id
text
}
}
}
}
您将在终端中看到复杂的嵌套地图。它包含我们需要的所有信息。选择包含字段。每个字段都有一个名称。如果它有一个嵌套对象,它又包含一个列表selections
。
现在我们只需要沿着兔子洞走下去,为我们的Dgraph查询收集信息并相应地构建它。由于它已经通过了苦艾酒验证等,它看起来是一个不错的选择。
有趣的是,如果这样的方法会导致Absinthe带来的优化问题,比如在已经获取的对象的内存缓存中......