问题
I'm trying to base a query on the number of documents in the child collection.
This is my context:
class Pro
include Mongoid::Document
has_many :recommendations
scope :lost, -> { where(:recommendation_ids => []) }
scope :normal, -> { where(:recommendation_ids.ne => []) }
end
And the child collection:
class Recommendation
include Mongoid::Document
belongs_to :pro
end
So, now I execute:
>> Pro.lost.count
0
>> Pro.all.select{|p| p.recommendations.count == 0}.count
1
What am I doing wrong? I've tried also with Pro.with_size(recommendation_ids: 0)
and some other variations but nothing new.
Any ideas would be highly appreciated, thanks in advance.
Moped 2.0.1, Mongoid 4.0.0, Rails 4.0.6
回答1:
You've coded the scope to search for IDs in an empty array, so it's always searching for an array of 0 ids.
scope :lost, -> { where(:recommendation_ids => []) }
Maybe something like this, if you want to pass an argument to it.
scope :lost, ->(rec_ids) { where(:recommendation_ids => [rec_ids]) }
回答2:
I tried to find a solution for this problem several times already and always gave up. I just got an idea how this can be easily mimicked. It might not be a very scalable way, but it works for limited object counts. The key to this is a sentence from this documentation where it says:
Class methods on models that return criteria objects are also treated like scopes, and can be chained as well.
So, instead of declaring a scope you can define a class function like so:
def self.lost
ids = Pro.all.select{|p| p.recommendations.count == 0}.map(&:id)
Pro.where(:id.in => ids)
end
The advantage is, that you can do all kinds of queries on the associated (Recommendations) model and return those Pro instances, where those queries are satisfied (which was the case for me) and most importantly you can chain further queries like so:
Pro.lost.where(:some_field => some_value)
来源:https://stackoverflow.com/questions/26911752/query-based-on-a-child-collection-count-with-has-many-association-is-showing-alw