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

Could this be used with GraphQL? #37

Open
vfonic opened this issue Jul 4, 2020 · 5 comments
Open

Could this be used with GraphQL? #37

vfonic opened this issue Jul 4, 2020 · 5 comments

Comments

@vfonic
Copy link

vfonic commented Jul 4, 2020

GraphQL generally works in a way that you can query exactly the fields (columns) that you want from the database like this:

{
  users {
    name
    posts {
      title
    }
  }
}

There's a very popular GraphQL gem for ruby: https://github.com/rmosolgo/graphql-ruby

Currently, the best solution that I've sees is using batch querying. It would looks something like this in reality:

users = User.all
posts = Post.find(user_id: users.map(&:id))

Perhaps this could be optimized using deep_pluck?
It would already be a huge improvement if it could pluck only requested fields:

users = User.pluck(:id, :name)
posts = Post.where(user_id: users.map(&:id)).pluck(:title)

Note that we also need to fetch user.id even though that's not in the query.

Any ideas how this could be achieved?
Could this be something that could be done on the graphql-ruby gem perhaps?

@khiav223577
Copy link
Owner

khiav223577 commented Jul 5, 2020

It will be difficult to use deep_pluck with GraphQL since it have to know all selected fields including nested child fields before querying. As far as I know, we can only get one-level child fields by using lookahead feature. (I found the feature in rmosolgo/graphql-ruby#2196 )

One possible way that may works is adding a wrapper type in the top of the types, and query all the data in it. Then use hash_key (I found the feature in rmosolgo/graphql-ruby#107) to lookup the value from the hash via the key.

For example: (I've not tested it yet)

module Types
  class UsersType < Types::BaseObject
    field :users, [UserType]

    def users
      batch do |ids| # TODO: replace batch method by your batch querying tool.
        User.where(id: ids).deep_pluck(:name, posts: [:title, :content])

        # Or select all columns of the model:
        # User.where(id: ids).deep_pluck(*User.column_names, posts: Post.column_names)
      end
    end
  end
end
module Types
  class UserType < Types::BaseObject
    field :name, hash_key: 'name'
    field :posts, [PostType], hash_key: :posts
  end
end
module Types
  class PostType < Types::BaseObject
    field :title, hash_key: 'title'
    field :content, hash_key: 'content'
  end
end

It will get a huge performance improvement even if we select all columns that are not to be used, in that we only load the raw data and do not instantiate the models.

@vfonic
Copy link
Author

vfonic commented Jul 6, 2020

It will be difficult to use deep_pluck with GraphQL since it have to know all selected fields including nested child fields before querying. As far as I know, we can only get one-level child fields by using lookahead feature. (I found the feature in rmosolgo/graphql-ruby#2196 )

It's actually possible to get all the nested child fields using lookahead. :)

Hey @rmosolgo, do you think any of these would make sense to look further into? It doesn't have to become a standard part of 'graphql-ruby', but perhaps an extension for active record that would allow for easy performance boost (and avoiding N+1 or even multiple (batch) queries)?
Do you see any downsides to this approach?

@rmosolgo
Copy link

rmosolgo commented Jul 7, 2020

I think it would be an awesome thing to look into! It's always been "theoretically possible" but I haven't heard of anyone who actually worked it out. Please share your results if you get something working!

@khiav223577
Copy link
Owner

It will be difficult to use deep_pluck with GraphQL since it have to know all selected fields including nested child fields before querying. As far as I know, we can only get one-level child fields by using lookahead feature. (I found the feature in rmosolgo/graphql-ruby#2196 )

It's actually possible to get all the nested child fields using lookahead. :)

@vfonic I took some time to learn graphql-ruby, and finally created a graphql project that uses deep_pluck to query data.
It's a very simple project while it shows it is possible to use deep_pluck with graphql-ruby.
See: khiav223577/rails-graphql-pluck-test#2

I think it would be an awesome thing to look into! It's always been "theoretically possible" but I haven't heard of anyone who actually worked it out. Please share your results if you get something working!

@rmosolgo You might also be interested in it :)

@vfonic
Copy link
Author

vfonic commented Aug 22, 2020

Daaaamn! At first glance, this looks amazing! Thank you, @khiav223577!

When I find time, I'll try to add this to my project and let you know how it goes. I'm currently using custom method that also relies on lookahead, but queries for all the fields. This seems like a better solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants