Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
EventMachine MongoDB Driver (based off of RMongo)
Ruby
tree: 1a8678f46d

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.
lib
spec
.gitignore
CHANGELOG
Gemfile
README.rdoc
Rakefile
VERSION
em-mongo.gemspec

README.rdoc

EM-Mongo

An EventMachine client for MongoDB. Originally based on RMongo, this client aims to be as api compatible with mongo-ruby-driver as possible.

For methods that do not retrieve data from the database, the api of em-mongo should be identical to the mongo-ruby-driver. This include the various update methods like insert, save and update (without the :safe flag, which is handled separately) as well as any data fetching methods, such as find, that return a cursor.

For operations that require IO, em-mongo always returns an EventMachine deferrable.

Some examples

“`ruby #insert a few records, then read some back using Collection#find

require 'em-mongo' require 'eventmachine'

EM.run do

db = EM::Mongo::Connection.new(:host => 'localhost').db('my_database')
collection = db.collection('my_collection')
EM.next_tick do
  (1..10).each do |i|
    collection.insert { :revolution => i }
  end

  #find returns an EM::Mongo::Cursor
  cursor = collection.find 

  #most cursor methods return an EM::Mongo::RequestResponse,
  #which is an EventMachine::Deferrable
  resp = cursor.to_a 

  #when em-mongo IO methods succeed, they 
  #will always call back with the return
  #value you would have expected from the 
  #synchronous version of the method from
  #the mongo-ruby-driver
  resp.callback do |documents|
    puts documents.inspect
  end

  #when em-mongo IO methods fail, they
  #errback with an array in the form
  #[ErrorClass, "error message"]
  resp.errback do |err|
    raise *err
  end
end

#iterate though each result in a query
collection.find( :revolution => { "$gt" => 8 } ).limit(1).each do |doc|
  puts doc.inspect
end  

#add an index
collection.create_index [[:revolution, -1]]

#insert a document and ensure it gets written
save_resp = collection.safe_save( { :hi => "there" }, :last_error_params => {:fsync=>true} )
save_resp.callback { puts "Hi is there, let us give thanks" }
save_resp.errback { |err| puts "AAAAAAAAAAAAAAAARGH! Oh why! WHY!?!?!" }

EM.stop

end

“`

Error handling

em-mongo will present errors in two different ways. First, em-mongo will raise exceptions like any other synchronous library if an error is enountered in a method that does not need to perform IO or if an error is encountered prior to peforming IO.

For errors returned by the database, or errors in communication or message processing, will be delivered via standard EM::Deferrable errbacks. While it is tempting to subscribe just to a callback

“`ruby my_colletion.find.to_a.callback {|docs| … } “`

in the case of an error you will never receive a response. If you are using em-synchrony or some other method to wait for a response before your program continues, you will be waiting a very long time. A better approach would be to store the deferrable into a variable and subscribe to its callback and errback

“`ruby resp = my_collection.find.to_a resp.callback { |docs| … } resp.errback { |err| raise *err } “`

errback's blocks will always be called with a single argument which is a two element array containing the error class and the error message

“`ruby

EM::Mongo::OperationError, “aw snap”

“`

Safe Writes

As you are probably aware the default behavior for the mongo-ruby-driver, and therefore em-mongo, is to send update messages to MongoDB in a fire-and-forget manner. This means that if a unique index is violated, or some other problem causes MongoDB to raise an exception and refuse to apply your changes, you'll never know about it until you go to look for that record later. For many applications such as logging this might be OK, but for many use cases like analytics you will want to know if your writes don't succeed.

This is one place where em-mongo diverges substantially from the mongo-ruby-driver because an unsafe write will not receive a response from the server, whereas a safe write will receive a response from the server and requires a deferrable and a callback.

“`ruby #default, unsafe write my_collection.insert( {:a => “b” } ) “`

“`ruby insert_resp = my_collection.safe_insert( {:a => “b” } ) insert_resp.callback do { #all ok } insert_resp.errback do { |err| puts '<sigh>' } “`

em-mongo has the following safe methods: safe_insert, safe_update, safe_save

In addition to calling your errback if the write fails, you can provide the usual 'safety' options that you can to Database#get_last_error, such as :fsync => true or :w => 2, to control the degree of safety you want. Please the 10gen documentation on DB#get_last_error for specifics.

Upgrading

The API for em-mongo has changed since version 0.3.6.

  • With the single exception of EM::Mongo::Collection#each, em-mongo methods no longer directly accept callbacks and instead return EM::Mongo::RequestResponse objects, which are EM::Deferrable(s). This means you need to convert calls like this

“`ruby my_collection.first() { |doc| p doc } “`

to this

“`ruby my_collection.find().callback { |doc| p doc } “`

  • EM::Mongo::Collection#find returns a cursor, not an array, to maintain compatibility with the mongo-ruby-driver. This provides a great deal more flexibility, but requires you to select a specific method to actually fetch data from the cursor, such as #to_a or #next

“`ruby my_collection.find() { |docs| … } “`

becomes

“` my_collection.find.to_a.callback { |docs| … } “`

If for some reason you aren't ready to upgrade your project but you want to be able to use the newer gem, you can require a compatibility file that will revert the new API to the API found in 0.3.6

“`ruby require 'em-mongo' require 'em-mongo/prev.rb' “`

This file will not remain in the project forever, though, so it is better to upgrade your projects sooner rather than later.

Features

Collection

Crud Operations

#find, #find_one, #save, @safe_save, #insert, #save_insert, #update, #safe_update, #remove, #find_and_modify

Index Management

#create_index, #drop_index

Collection Management

#drop, #stats, #count, #name

Server Side Aggregations

#map_reduce, #group, #distinct

Database

Collection Management

#collection, #collection_names, #collections, #collections_info, #create_collection, #drop_collection

Index Management

#drop_index, #index_information

Authentication

#authenticate, #add_user

Misc

#get_last_error, #error?, #name, #command

Cursor

Query options

:selector, :order, :skip, :limit, :explain, :batch_size, :fields, :tailable, :transformer

Enumerable-ish

**EM::Mongo::Cursor does *not* use the Enumerable mixin for obvious reasons** #next_document, #rewind!, #has_next?, #count, #each, #to_a

Misc

#batch_size, #explain, #close, #closed?

Query modifier methods

#sort, #limit, #skip

Still Missing / TODO

  • Replica Sets

  • GRIDFS support

  • Connection pooling

Examples

require 'em-mongo'

EM.run do
  db = EM::Mongo::Connection.new.db('db')
  collection = db.collection('test')
  EM.next_tick do
    doc = {"hello" => "world"}
    id = collection.insert(doc)
    collection.find('_id' => id]) do |res|
      puts res.inspect
      EM.stop
    end
    collection.remove(doc)
  end
end

Todo

  1. -Refactor unit tests and make them more comprehensive-

  2. collection.index

  3. Server side aggregate functions (reference)

Contact

  • Twitter: @brendengrace

  • IRC: bcg

  • Email: brenden.grace@gmail.com

Credit

Aman Gupta (tmm1) wrote the original RMongo which em-mongo is based on.

References

License

(The MIT License)

Copyright © 2010

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ‘Software’), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Something went wrong with that request. Please try again.