Getting Started with MongoDB & MongoMapper

As part of our NoSQL exploration, I’ve spent some time lately with MongoDB. MongoDB bills itself as a “schema-free document-oriented database.” In using MongoDB, I’ve found it to be an easy transition from RDBMS’s because of the way it organizes document-based data. Here’s the basics:

  • MongoDB has collections of data, not tables. Unlike CouchDB, which is also a document-oriented DB, Mongo has namespaces for data. These are schema-less, so any data could go in each namespace. In my practice, I’ve persisted objects of one class into each collection, not unlike ActiveRecord with MySQL or any other RDBMS.

  • MongoDB has indexes. Even though each collection has no schema, you can still index the data in a collection based off a field. Not all documents in a collection have to have this field.

  • MongoDB has a query language and query profiling. While you can use JavaScript to search through a collection, like CouchDB, you also have access to a rich query language that can filter based on fields, like SQL, and filter based on the contents of embedded documents, which proves to be totally freaking awesome. Instead of a complex join, you can query for all documents in the posts collection that have an embedded comment in the last month.

Given the similarities between MongoDB and a relational database, you’d think it would be easy to use in Ruby in place of ActiveRecord, and you’d be right. John Nunemaker has created a gem called MongoMapper to work as an object mapper to MongoDB. Using MongoMapper, you can create model classes like so:

class Book include MongoMapper::Document key :title, String, :required => true key :author, String key :published_at, Date key :user_id, String timestamps! # HECK YES belongs_to :user many :chapters end 

You’ll note several things here. Keys are defined in the model, like in a DataMapper model, although they aren’t defining a schema, only a mapping for this particular model. (If the difference seems subtle, that’s because it is: MongoMapper in many ways lets you treat MongoDB as a relational DB.) The keys can be typecast as I’ve done, although they don’t have to be. I’ve defined relationships to other models, and MongoMapper is smart about this. In the case of many :chapters, it looks to see if the Chapter class is embeddable. If so, it will embed Chapter documents in my Book document. If not, it will store them in their own collection.

Just because MongoMapper defines a document with keys, you don’t have to stick to the keys. Because collections are schema-less, you can add new attributes at will, like in this example:

book = Book.new(:title => "Moby Dick 2") # => #<Book _id: , title: Moby Dick 2, author: > book.author = "Dan Brown" book.update_attributes(:author => "J.K. Rowling", :isbn => '1-2345-6789-0', :amazon_score => 1.25) book.save book = Book.find_by_title("Moby Dick 2") # => #<Book _id: 4aafe487477a51f0e8000002, # title: Moby Dick 2, # author: J.K. Rowling, # isbn: 1-2345-6789-0, # amazon_score: 1.25> 

You can see that I can set keys defined in the class with setters, but I can set any attribute through update_attributes.

MongoMapper’s API is roughly equivalent to ActiveRecord’s, allowing you to use in a Rails application with little difficulty. The only things I’ve had to do are define human_name on model classes and define new_record? on embedded documents.

The only other thing you need to know to get started with MongoMapper is how to tell it what database to use. All you have to do is set MongoMapper.connection and MongoMapper.database. In my sample Rails app, I’ve put a file in config/initializers/ that looks like this:

db_config = YAML::load(File.read(RAILS_ROOT + "/config/database.yml")) if db_config[Rails.env] && db_config[Rails.env]['adapter'] == 'mongodb' mongo = db_config[Rails.env] MongoMapper.connection = Mongo::Connection.new(mongo['hostname']) MongoMapper.database = mongo['database'] end 

You can see my database.yml file for more information on setup or check out Ben Scofield’s Rails template for MongoMapper.

That should get you started! I’ve really enjoyed using MongoDB so far. For further information, checkout the MongoDB Ruby driver code, the MongoMapper code, and the code for my sample app on GitHub, and look out for more upcoming posts about how we’ve used MongoDB.

Clinton R. Dreisbach

,
Posted in Article Category: #Code
on