2

2 models:

Class User
 include Mongoid::Document
 has_many :reports
end

Class Report
 include Mongoid::Document
 belongs_to :user
end

I need a query to get all users have 6 or more reports, something like:.

Users.where(reports.count > 5)

I use mongo id 2.4.12

How can I do it?

Thank you very much!

hyperrjas
  • 10,666
  • 25
  • 99
  • 198

3 Answers3

1

Ok, This query is not possible since MongoDB does not have joins.

The fix for this problem is use a counter cache.

The first option is make a counter cache something like:

class User
  include Mongoid::Document
  field :reports_count, type: Integer
  has_many :reports
end

class Report
  include Mongoid::Document
  belongs_to :user
  after_create do |doc|
    doc.user.inc(:reports_count, 1)
  end
  after_destroy do |doc|
    doc.user.inc(:reports_count, -1)
  end
end

The second option (I have used this option) is use this gem https://github.com/jah2488/mongoid-magic-counter-cache.

For this question:

Models:

class User
 include Mongoid::Document
 field :report_count
 has_many :reports
end

Class Report
 include Mongoid::Document
 include Mongoid::MagicCounterCache
 belongs_to :user
 end

Inside a helper for example:

def users_with_reports_greather_than_5
 users_with_reports_greather_than_5 = []
 for u in User.where(report_count.ne => nil)
  if u.report_count > 5
   users_with_reports_greather_than_5 << u
  end
 end
 return users_with_reports_greather_than_5.count
end

Regards!

hyperrjas
  • 10,666
  • 25
  • 99
  • 198
0

You can use:

User.collection.find({"reports" => {"$size" => 5}}).count

to get the users who have 5 reports but to get the users who have more than 5 reports you'll have to keep an extra field (reports_count) which increments every time a new report is added. You can apply conditions on embedded documents as mentioned here: ( http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24size )

aash
  • 1,323
  • 1
  • 14
  • 22
  • Thank you but I get `undefined method 'count' for 0:Fixnum`. I use mongo id 2.4.12. This query is working fine for me now: `User.all.select {|user| user.reports.count > 5 }` Thank you! – hyperrjas Nov 07 '12 at 16:02
  • @hyperrjas, `User.all.select {|user| user.reports.count > 5 }` its not an correct approach. What you are doing is retrieving and loopinn all the users & reports in the database to find the report count. Check my answer for the correct way to do it mongo way – RameshVel Nov 07 '12 at 17:41
0

You need to use mongodb aggregation framework to find the users who got the more than 5 reports

In mongo shell

db.reports.aggregate(
                     // Group by user_id      
                     {$group:{_id:'$user_id',count:{$sum:1}, 

                      // Add the fields to result set along with grouped result
                      name:{$addToSet:'$any_field_you_need_to_return'}}}, 

                     // And return only the users who got greater than 5 reports
                     {$match:{count:{$gt:5}}}) 

Update

Aggregate only introduced in moped v1.3. You need to make a change in your gemfile to install the latest moped and run bundle install

  gem 'moped', :git=>'https://github.com/mongoid/moped.git', :branch => "master"

And you can use aggregate like

Reports.collection.aggregate(
                  {'$group' => {'_id' => '$user_id','count' => {'$sum' => 1},
                   'name' => {'$addToSet' => '$any_field_you_need_to_return'}}},
                  {'$match' => {'count' => {'$gt' => 5 }}})
RameshVel
  • 64,778
  • 30
  • 169
  • 213
  • Thank you. Can you write a query for mongoid odm? How can I add this query to my rails app? Thank you very much! – hyperrjas Nov 07 '12 at 22:16
  • Thank you I get this error: `undefined method 'aggregate' for #`. The model `Reports` not exists. The model is `Report`. I use mongo id 2.4.12. I need a query to get all users have 6 or more reports. Thank you very much! – hyperrjas Nov 08 '12 at 09:56
  • You need to use mongoid 3.0 or 4.0 with moped 1.3.. can you check your gem versions – RameshVel Nov 08 '12 at 14:35
  • `to get all users have 6 or more reports`, you need to change `{'$gt' => 5 }` this to `{'$gte' => 6 }` – RameshVel Nov 08 '12 at 14:37
  • Sorry but my project is mongoid 2.x.x. This response is for mongoid 3+. – hyperrjas Nov 08 '12 at 14:51