Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to access requested fields in resolver #287

Closed
vladshcherbin opened this Issue Mar 9, 2017 · 10 comments

Comments

Projects
None yet
5 participants
@vladshcherbin
Copy link

vladshcherbin commented Mar 9, 2017

The resolver from the example:

defmodule Blog.PostResolver do
  def all(_args, _info) do
    {:ok, Blog.Repo.all(Post)}
  end
end

This will select all fields from database, no matter what fields you request in the query.

Is there any example, how to select only requested fields from the database? Some kind of this:

defmodule Blog.PostResolver do
  def all(_args, _info) do
    fields = ?
    {:ok, Post |> select(fields) |> Blog.Repo.all}
  end
end
@benwilson512

This comment has been minimized.

Copy link
Contributor

benwilson512 commented Mar 10, 2017

Hey! You can find the fields under info.definition.fields.

FWIW unless the column contains particularly large amounts of information you don't get a very large speed up from dynamically selecting fields.

@vladshcherbin

This comment has been minimized.

Copy link
Author

vladshcherbin commented Mar 18, 2017

@benwilson512 that's one of the problems with graphql.

Everyone says that it's so cool and how it is easy to write stuff, but things like preloading (to avoid lots of queries) are often not even mentioned.

Same with selects - sure, when you have small tables, it may be possible that you don't need it. What about medium or large apps, where you have lots of columns and for example a mobile app wants 2 fields from 30. You know fields, but select all.

I really don't understand it, selects were meant to select necessary fields, not just wildcard all. It would be great to have at least an example in the docs (like with preloads) because people forget this or think that library will do this for them.

@benwilson512

This comment has been minimized.

Copy link
Contributor

benwilson512 commented Mar 19, 2017

I don't think this is an issue with GraphQL itself, but rather just an issue with the fact that as a newer technology there's simply less tooling available so far for adapting it to different scenarios.

GraphQL itself doesn't say anything about preloading or selects because such concerns are very specific to whatever data store you're actually using.

What you'll see is that in each main language that uses GraphQL there has been quite a bit of tooling developed to get the desired functionality out of various kinds of data sources. https://github.com/facebook/dataloader and https://github.com/stems/join-monster come to mind in the JS world, https://github.com/Shopify/graphql-batch in the Ruby world, and we've been working on https://github.com/absinthe-graphql/absinthe_ecto for Elixir users.

@bruce

This comment has been minimized.

Copy link
Member

bruce commented Mar 19, 2017

To piggy back on @benwilson' comment -- a selection set determines what data to return, not necessarily what data to retrieve from an underlying data store, which may or may not support selection of individual fields, and may or may not even have those fields to begin with (one of GraphQLs greatest uses, in my opinion, as an abstraction layer on top of the underlying data). So, no, you don't get automatic database field selection without having to do some work, but with a bit of tooling you can -- and we're working on making that easier, too.

@vladshcherbin

This comment has been minimized.

Copy link
Author

vladshcherbin commented Mar 19, 2017

Yes, I fully agree with you guys. Fine tuning graphql needs some work and knowledge, that's why an official example would be great for devs, who are just starting and have this questions, especially since Absinthe has guides (Ecto Best Practices is a good example).

@jeroenhouben

This comment has been minimized.

Copy link

jeroenhouben commented Sep 26, 2017

Thanks @benwilson512 !

@vladshcherbin I use this. Thinks it's pretty generic

  defp select_schema_fields(queryable, %Absinthe.Resolution{} = info) do
    fields = info.definition.selections
    |> Enum.map(&(Map.get(&1, :name)|>String.to_atom))

    queryable
    |> select(^fields)
  end

and:

    DbTable
    |> select_schema_fields(info)
    |> Repo.all

Think its generic enough.

ps I'm not an elixir expert. And the code where I collect the field atoms seems rather cryptic, perhaps it could be coded better?

@jeroenhouben

This comment has been minimized.

Copy link

jeroenhouben commented Sep 26, 2017

I agree with @vladshcherbin that not limiting fields defeats somewhat the purpose of graphql/absinthe. I have rather wide database views large text columns. And the db server is not on the same server as Phoenix. Should make some difference on large row counts.

@benwilson512

This comment has been minimized.

Copy link
Contributor

benwilson512 commented Sep 26, 2017

FYI the options here have come a long way since this original issue. The https://hexdocs.pm/absinthe/Absinthe.Resolution.html#project/1 function makes it much easier to cleanly get subfields under the existing field.

I do think that more selective column retrieval is valuable, but there is literally nothing in Absinthe that prevents people from doing so, it's just a matter of building a mapping from fields (which are easily retrieved) to db columns.

There absolutely could be more tooling there, but it's the kind of tooling we'd be interested in the community stepping up to build, since the core team's focus at the moment has to be stuff like subscriptions or schema refactoring that can't feasibly be done by others.

@mgwidmann

This comment has been minimized.

Copy link

mgwidmann commented Sep 27, 2017

I've found that this is particularly helpful to use when you have a field that requires preloading of 1 or more relationships in order to compute. project/1 allows you to look to see if that heavy field is requested and modify the preload accordingly.

👍

@benwilson512

This comment has been minimized.

Copy link
Contributor

benwilson512 commented Sep 27, 2017

@mgwidmann Yup, definitely an option. I'd also consider experimenting with Batching, you can usually achieve the same thing that way, and it has the plus side of keeping the parent field simpler.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.