I'm still getting the hang of MongoDB and Mongoid and have hit this snag.
Let's say I have a User
that has_and_belongs_to_many
items
and of course an Item
that has_and_belongs_to_many
users
.
I'd like to be able to count the Users with any Items.
this question recommended adding a scope
so I tried adding a scope to User
such as
scope :has_no_items, where(:items.empty?)
but User.count - User.has_no_items.count
returns 0
.
I've looked at .with_size
but that's specific to Array fields.
What is the correct way to do this other than
count = 0
User.each { |u| count += 1 unless u.items.empty? }
which works but it doesn't seem very elegant.
How do I do this efficiently?
The following works for me with Rails 3.2.13, Mongoid 3.1.4, Moped 1.5.0.
app/models/user.rb
class User
include Mongoid::Document
field :name, type: String
has_and_belongs_to_many :items
scope :has_items, where(:item_ids.ne => nil)
scope :has_no_items, where(:item_ids => nil)
end
app/models/item.rb
class Item
include Mongoid::Document
field :name, type: String
has_and_belongs_to_many :users
end
test/unit/user_test.rb
require 'test_helper'
class UserTest < ActiveSupport::TestCase
def setup
User.delete_all
Item.delete_all
end
test "users without items" do
fagin = User.create(:name => 'Fagin')
oliver = User.create(:name => 'Oliver')
fagin.items << Item.create(:name => 'cane')
assert_equal 2, User.count
assert_equal 1, Item.count
assert_equal 1, User.has_items.count
assert_equal 1, User.has_no_items.count
puts
puts "User.has_items: #{User.has_items.to_a.inspect}"
puts "User.has_no_items: #{User.has_no_items.to_a.inspect}"
end
end
rake test
Run options:
# Running tests:
[1/1] UserTest#test_users_without_items
User.has_items: [#<User _id: 51df00987f11ba3d7d000001, name: "Fagin", item_ids: ["51df00987f11ba3d7d000003"]>]
User.has_no_items: [#<User _id: 51df00987f11ba3d7d000002, name: "Oliver", item_ids: nil>]
Finished tests in 0.042205s, 23.6939 tests/s, 94.7755 assertions/s.
1 tests, 4 assertions, 0 failures, 0 errors, 0 skips
Hope that this helps.