Mongoid embedded helper
The Mongoid EmbeddedHelper helps overcome the limitation that you can’t perform direct queries on an embedded collection without accessing it from the root. It simply introduces a generic function that performs the “local” query by accessing it from the nearest root ;)
Update June 24, 2011
In the latest release (0.3.1) the gem has been tested to work with Mongoid 2.0.2 (run the specs!)
Install
In Gemfile:
gem 'mongoid_embedded_helper'
Run bundler
$ bundle
Usage
Mongoid doesn’t allow you to perform direct queries on an embedded collection. You have to access the embedded collection from the root in order to do this.
To overcome this limitation, use the EmbeddedHelper module to add a method query_class
which will find the closest non-embedded node in the hierarchy and
then traverse down the path back to the object, so that you can perform the query on the embedded collection.
require 'mongoid_embedded_helper'
class Item
include Mongoid::Document
include Mongoid::EmbeddedHelper
field :pos, :type => Integer
field :number, :type => Integer
field :assoc, :type => Symbol
:list, :inverse_of => :items
end
item = @person.lists[0].items[0]
item.query_class.where(:number.gt => 1).to_a
Adjust!
An as added bonus, an extra adjust! method has been added to Document, Criteria and Array. This enables multi-mutation of attributes! This functionality comes along from the mongoid_adjust gem.
Here an example using a number
it "should times all positions (greater than 1) by 2" do
result = @person.lists[0].items.where(:pos.gt => 1).adjust!(:pos => lambda {|e| e * 2})
result.map(&:pos).should == [4, 6]
end
Passing a number is a convenience shortcut for adding a number instead of having to use the Proc approach as shown below.
Here an example using a lambda (or Proc):
it "should times all positions (greater than 1) by 2" do
result = @person.lists[0].items.where(:pos.gt => 1).adjust!(:pos => lambda {|e| e * 2})
result.map(&:pos).should == [4, 6]
end
The Proc approach can in simple cases be declared using a shortcut Symbol/String approach
Here an example using a symbol :upcase to declare that the method #upcase should be used as the mutator:
it "should upcase the name - using symbol arg" do
result = @person.adjust!(:name => :upcase)
result.name.should == 'Kristian'.upcase
end
And using a String ‘upcase’ instead of a symbol:
it "should upcase the name - using symbol arg" do
result = @person.adjust!(:name => 'upcase')
result.name.should == 'Kristian'.upcase
end
Copyright
Copyright © 2010 Kristian Mandrup