Find all records which have a count of an association greater than zero

后端 未结 10 1620
北海茫月
北海茫月 2020-11-30 17:45

I\'m trying to do something that I thought it would be simple but it seems not to be.

I have a project model that has many vacancies.

class Project &         


        
10条回答
  •  攒了一身酷
    2020-11-30 17:55

    Performing an inner join to the has_many table combined with a group or uniq is potentially very inefficient, and in SQL this would be better implemented as a semi-join that uses EXISTS with a correlated subquery.

    This allows the query optimiser to probe the vacancies table to check for the existence of a row with the correct project_id. It doesn't matter whether there is one row or a million that have that project_id.

    That's not as straightforward in Rails, but can be achieved with:

    Project.where(Vacancies.where("vacancies.project_id = projects.id").exists)
    

    Similarly, find all projects that have no vacancies:

    Project.where.not(Vacancies.where("vacancies.project_id = projects.id").exists)
    

    Edit: in recent Rails versions you get a deprecation warning telling you to not to rely on exists being delegated to arel. Fix this with:

    Project.where.not(Vacancies.where("vacancies.project_id = projects.id").arel.exists)
    

    Edit: if you're uncomfortable with raw SQL, try:

    Project.where.not(Vacancies.where(Vacancy.arel_table[:project_id].eq(Project.arel_table[:id])).arel.exists)
    

    You can make this less messy by adding class methods to hide the use of arel_table, for example:

    class Project
      def self.id_column
        arel_table[:id]
      end
    end
    

    ... so ...

    Project.where.not(
      Vacancies.where(
        Vacancy.project_id_column.eq(Project.id_column)
      ).arel.exists
    )
    

提交回复
热议问题