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
  embedded_in :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