Reputation: 683
I have this method in my Product model that does what I need:
def self.available
available = []
Product.all.each do |product|
if product.quantity > product.sales.sum(:quantity)
available << product
end
end
return available
end
But, I am wondering if there is a more efficient way to do this, maybe with only one call to the database.
Upvotes: 3
Views: 120
Reputation: 52336
Well you might try:
Product.where("products.quantity > Coalesce((select sum(s.quantity) from sales s where s.product_id = products.id), 0)")
Upvotes: 3
Reputation: 4322
This creates a number of queries equal to the number of products you have due to the sum
query. Here is a way I though of that will reduce database queries.
map = Sale.joins(:product)
.group("products.id", "products.quantity").sum(:quantity).to_a
Which will produce an array similar to
[[[1,20],30], [[2,45], 20]]
this corresponds to [[[product_id, product_quantity], sold_quantity ]]
Now loop over this array and compare the values.
available = []
map.each do |item|
if item[0][1] > item[1]
available << item[0][0]
end
end
Now that you have the available
array populated, perform another query.
available = Product.where(id: available)
Now you got your same output in two queries instead of Product.count (N)
number of queries. This solution can be inefficient sometimes but I will be updating it regularly if I had any ideas.
Upvotes: 0