Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pluck associated model's attribute in Rails query

In my rails app, collections have many projects, and projects have many steps.

I'd like to grab all the ids of steps in a collection's projects, and I'm wondering if I can do it all in one query.

For example, I know I can do the following

step_ids = []
@collection.projects.each do |project|
    project.steps.each do |step|
       step_ids << step.id
    end
end

But is it possible to do something like the following:

@collection.projects.include(:steps).pluck("step.id") // syntax here is not correct

like image 849
scientiffic Avatar asked Oct 23 '14 22:10

scientiffic


People also ask

Is pluck faster than map?

Prefer pluck instead of map Using pluck will be faster, because it doesn't need to load an entire object into memory. For this particular case, pluck is six times faster than map .

How does pluck work?

What the pluck () function does is that it essentially loops through a collection and collects all the data from the particular field and stores it in another collection. That would mean, it plucks the concerned value from a large set of data and stores them in a separate collection for later usage.


2 Answers

Try this:

Step.joins(:project).where(projects: { collection_id: @collection.id }).pluck(:'steps.id')

Note the use of project for the joins, and then projects for the where clause. The first corresponds to the belongs_to relationship, and the latter is the name of the db table.

edit: in the case of a many-to-many relationship between projects and collections, and assuming a project belongs_to a project_collection (and then has_many :collections, through :project_collection)

Step.joins(:project => :project_collection)
    .where(project_collections: { collection_id: @collection.id })
    .pluck(:'steps.id')
like image 105
John Avatar answered Oct 07 '22 02:10

John


Unfortunately, I don't think that we could do it through AR in a single query. You could do a nested query below to retrieve it in two queries to the database:

Step.includes(:projects)
    .where(projects: { id: Projects.includes(:collections)
    .where(collections: { id: @collections.id }).pluck(:id) } )
    .pluck(:id)
like image 24
nikkon226 Avatar answered Oct 07 '22 02:10

nikkon226