ActiveRecord: exclude a group if at least one record in it does not meet the condition

I have two models: a ownerand a pet. Owner has_many :petsand pet belongs_to :owner.

What I want to do is to capture only those owners who have pets that are ALL weighing more than 30 pounds.

 
#app/models/owner.rb
class Owner < ActiveRecord::Base
  has_many :pets
  #return only those owners that have heavy pets
end

#app/models/pet.rb
class Pet < ActiveRecord::Base
  belongs_to :owner
  scope :heavy, ->{ where(["weight > ?", 30])}
end

Here is what is in my database. I have three owners:

  • Neil, and ALL of which are hard,
  • John, and ALL of which are NOT heavy,
  • Bob, and SOME of his pets are heavy and SOME, NOT HER.

The request should return only Neil. Right now, my attempts are returning Neil and Bob.

+4
source share
4 answers

, , owner_ids, 1 , owner_ids, 1 , , id , ?

- :

scope :not_heavy, -> { where('weight <= ?', 30) }     

...

owner_ids = Pet.heavy.pluck(:owner_id) - Pet.not_heavy.pluck(:owner_id)
owners_with_all_pets_heavy = Owner.where(id: owner_ids)
+1

owner_id , , group by having:

scope :heavy, -> { group("owner_id").having(["count(case when weight <= ? then weight end) = 0", 30]) }

, Rails-ActiverRecord:

scope :heavy, -> { where.not(owner_id: Pet.where(["weight <= ?", 30]).distinct.pluck(:owner_id)).distinct }

owner_id, ( ) .

+4

, , - :

scope :heavy, -> { group("owner_id").joins(:pets).having("min(pets.weight) >= ?", 30)}

,

scope :light, -> { group("owner_id").joins(:pets).having("max(pets.weight) < ?", 30)}

, , Pet

, :

Owner.where(Pet.where.not("pets.owner_id = owners.id and pets.weight < ?", 30).exists)

, 30, , , .

.

(owner_id, weight).

+3

uniq :

scope :heavy_pets, -> { uniq.joins(:pets).merge(Pet.heavy) }

, distinct.

+1
source

All Articles