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 ;)
In the latest release (0.3.1) the gem has been tested to work with Mongoid 2.0.2 (run the specs!)
In Gemfile:
gem 'mongoid_embedded_helper'
Run bundler
$ bundle
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 embedded_in :list, :inverse_of => :items end item = @person.lists[0].items[0] item.query_class.where(:number.gt => 1).to_a
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 © 2010 Kristian Mandrup