As pointed out in the comments, you can use map / reduce for this purpose. That way you can define the following method in your model ( http://mongoid.org/en/mongoid/docs/querying.html#map_reduce )
def self.today map = %Q{ function() { emit(this.course_id, {count: 1}) } } reduce = %Q{ function(key, values) { var result = {count: 0}; values.forEach(function(value) { result.count += value.count; }); return result; } } self.where(:created_at.gt => Date.today, status: "played"). map_reduce(map, reduce).out(inline: true) end
which will result in the following result:
[{"_id"=>1.0, "value"=>{"count"=>2.0}}, {"_id"=>2.0, "value"=>{"count"=>1.0}}]
where _id
is course_id
and count
is the number of pieces.
MongoDB also has a special group method, but I'm not sure how to get into the bare mongodb collection in Mongoid 3. I had no chance to dive even further into the code.
You may wonder why I am emitting the document {count: 1}
since it is not a big deal, and I could just release an empty document or something else, and then always add 1 to result.count for each value. The fact is that the reduction is not called if only one of them was made for a specific key (in my example, course_id
was played only once), so it is better to select documents in the same format as the result.
source share