My first real project using MongoDB (Rails + MongoMapper)



Written by Anthony Heukmes on Tue Jan 05 16:01:23 UTC 2010

15 comments



This article is not an introduction to MongoDB or MongoMapper.
It's a summary of a few things I learned while I was working on my first real project based on MongoDB.
You will find here some tips that will (I hope) help you during your MongoMapper learning phase.



I've been working recently on a project for a client who wanted to sell second-hand vehicles on his website.
It's a classic story : visitors can register and post announces describing the vehicle they'd like to sell.
Various vehicles types are available : cars, bikes, trucks and more.



Each announce is characterized by various attributes depending on the selected vehicle type.
You can find general information (brand, mileage, ...), information on the equipment (GPS? Radio?), the contact person, some pictures... and more.
Of course, the equipment of a truck and a bike will be very different!



I've been thinking for a while about the best way to structure my SQL schema but I was never satisfied with the results.
It was either too complicated to implement or to maintain and I also had the impression that the solution was not pretty enough.



Being addicted to new technologies, I directly took this opportunity to jump into the NoSQL world and start learning MongoDB, a documents oriented database more and more popular in the Rails community.



When I think about it, it's so much more beautiful to represent announces as documents, containing various subdocuments (general info, equipment, pictures...) instead of a couple of rows in SQL tables.



Notice that I'm using ActiveRecord (AR) an MongoMapper (MM) in the same project (because I installed my CMS engine) and it's working perfectly!



First steps



MongoMapper is very easy to learn because it mainly respects the ActiveRecord API. You will not be lost in a unknown world because you will be able to manipulate your documents as you are currently doing with your AR records. You can persist documents using well-known methods like save, create and update_attributes. You can also select the data you need using finders and conditions. Associations, callbacks and validation are available as well. In fact, the views and the controllers generated by a scaffold can directly be used as they are with MongoMapper.



That being said, don't think that learning MM will be as easy as pie. This is because your brain is currently SQL formated!
During the development of your project you will ask yourself a few questions and you'll have to search to find the answer.
For example, how can you execute a search on text fields? With SQL, you know that you have to use LIKE. But what is the equivalent with MongoDB?



MongoMapper is a young project and it is still under heavy development. There is currently no documentation, no books and only a few people are blogging about it.
The best place to get help is the Google group.



Once familiarized with the beast, you'll probably not want to come back to ActiveRecord.
After two full months of Mongo I had to get back to ActiveRecord and this is probably only at that time that I really realized the awesomeness of MongoMapper.



It was hard to remember migrations syntax and rake tasks to execute them... With MongoMapper, these painful migrations are gone!



The biggest disadvantage of the MongoMapper-ActiveRecord switch is that you loose most of your plugins. I'm for example a fan of Authlogic and I had to drop it. This is probably a matter of time because I know that his author is working on a MM compatible version. Some plugins will still work, like the excellent will_paginate for example.



Also, some very used features of ActiveRecord like named scopes aren't available yet.



Embedded Documents



MongoDB allows you to create embedded documents. In my personal case, an Announce can contain multiple pictures :





At the beginning it maybe difficult to determine whether or not you should use classic or embedded documents.
To help you in your choice, I will tell you when not to use embedded documents.



It's important to know that an EmbeddedDocument has a very limited set of methods.
For example, you cannot call the find method on a such object.



Following instructions are not valid :





So if you want to be able to manipulate a document independently of his parent, you should not use an embedded document.
These documents are mostly manipulated using classic Ruby code.



To create a new embedded document :





To select a document :





a.pictures returns a simple Ruby Array, the select method is a classical Ruby method, it has nothing to do with MongoMapper.



If you want to edit a document :





Note that you have to call the save method on the main document (the announce in this case).



Finally, here is the code to delete an embedded document :






Associations



You will find many examples on the Internet using the String type to declare "foregin keys".
But this is deprecated and should not be used anymore with new versions of MM.



Use ObjectID instead :





At your first tries you will also probably try to find an equivalent of the ActiveRecord has_one association.
We don't need that with MongoMapper because keys are not limited to basic types.



If you want to specify that a user has one profile, you just have to define your key like this :





The Profile class can for example be an EmbeddedDocument.




Finders



Let's come back to one of my first questions : how can you execute a search on text fields (equivalent of LIKE in SQL)?
By using regular expressions!





All users containing "thony" in their email address will be returned.
The /i allows us to specify that we want to ignore the case.



As you understood, you'll be able to perform very precise research if you refresh your skills in Javascript regular expressions.



What if I want to find all users created today? You can use $gt (greater than) and $lt (lower than) :





And finally, how do you find articles matching the searched keyword in their title OR description?
We'd like to generate a OR instead of a AND :






Testing



I use Machinist a lot to generate fake data in my specs.
Happily, an adapter exists for MongoMapper and you can find it on GitHub.



Just install the gem (gem install machinist_mongomapper) then edit your blueprints.rb file to load the new adapter (require 'machinist/mongomapper').



As you probably noticed, Mongo IDs are not simple numbers.
If you have to generate fake IDs in your tests, the following method is for you : Mongo::ObjectID.new




My plugins



I'll finish this article by promoting two plugins I recently developed :



- mongo_admin : generate an admin interface for your MongoMapper models. Demo available here.

- mongo_translation : allows you to internationalize (I18n) your MongoMapper models very easily.
Bookmark and Share

Add a comment



15 comments for this article



Also MongoMapper's tests are a good set of examples:

http://github.com/jnunemaker/mongomapper/tree/master/test/


Written by Roy Wright on Tue Jan 05 18:00:38 UTC 2010

Nice article, thanks.

I've just started using MongoMapper and, like you, missed a few plugins.

Devise (http://github.com/plataformatec/devise) is an excellent authentication solution that works out of the box with MongoMapper.


Written by Martin Stannard on Wed Jan 06 05:24:29 UTC 2010

Awesome exactly what i was looking for...


Have you got more information on how you manage categories like cars, bike,....


Written by blah on Thu Jan 07 06:00:03 UTC 2010

Thanks for sharing. I was looking for an admin plugin. mongo_admin looks cool! Any plans to integrate with devise which is based on warden?


Written by Jai-Gouk Kim on Tue Jan 19 15:07:28 UTC 2010

Bonjour,

Vous utilisez rails 2 ou rails 3 avec MongoMapper ?

Sinon bel article !


Written by rivsc on Tue Mar 23 16:51:48 UTC 2010

That's good that people are able to receive the <a href="http://bestfinance-blog.com">loans</a> and that opens up completely new possibilities.


Written by Leola34Phelps on Mon Aug 16 06:35:57 UTC 2010

I did use mongo_mapper, mongoDB and Rails for my project too...

http://solimap.com

Now I can't code with mysql ;)


Written by solimap on Mon Sep 27 15:46:54 UTC 2010

Superior thinking demonstrated above. Tankhs!


Written by Superior thinking demonstrated above. Tankhs! on Tue May 10 02:36:49 UTC 2011

You've hit the ball out the park! Incredilbe!


Written by You've hit the ball out the park! Incredilbe! on Tue May 10 12:04:15 UTC 2011

9UQEJc <a href="http://pfedmvevqfqx.com/">pfedmvevqfqx</a>


Written by 9UQEJc <a href="http://pfedmvevqfqx.com/">pfedmvevqfqx</a> on Wed May 11 04:06:43 UTC 2011

XSIJDP , [url=http://wbsamgyshhtn.com/]wbsamgyshhtn[/url], [link=http://fndjlctitqck.com/]fndjlctitqck[/link], http://dikmhcktumfy.com/


Written by XSIJDP , [url=http://wbsamgyshhtn.com/]wbsamgyshhtn[/url], [link=http://fndjlctitqck.com/]fndjlctitqck[/link], http://dikmhcktumfy.com/ on Wed May 11 12:18:27 UTC 2011

Real brain power on dpsilay. Thanks for that answer!


Written by Real brain power on dpsilay. Thanks for that answer! on Wed May 11 14:34:42 UTC 2011

Superior thinking demonstrated above. Thakns!


Written by Superior thinking demonstrated above. Thakns! on Wed May 11 14:49:12 UTC 2011

Dje2Oh , [url=http://yummqdjbjyqg.com/]yummqdjbjyqg[/url], [link=http://pfozscgrobvj.com/]pfozscgrobvj[/link], http://kdhxxlhhiiik.com/


Written by Dje2Oh , [url=http://yummqdjbjyqg.com/]yummqdjbjyqg[/url], [link=http://pfozscgrobvj.com/]pfozscgrobvj[/link], http://kdhxxlhhiiik.com/ on Sat May 28 17:28:04 UTC 2011

Iy3JAP , [url=http://zylqiqsnxvir.com/]zylqiqsnxvir[/url], [link=http://crxbdqncyufj.com/]crxbdqncyufj[/link], http://hmjjbgrrlbpy.com/


Written by Iy3JAP , [url=http://zylqiqsnxvir.com/]zylqiqsnxvir[/url], [link=http://crxbdqncyufj.com/]crxbdqncyufj[/link], http://hmjjbgrrlbpy.com/ on Sat May 28 18:09:07 UTC 2011