Sonntag, 15. Februar 2015

Store documents in MongoDB!

MongoDB has become the synonym for NoSQL databases. It is like the shiny new toy every kid wants to play around with. And that is why it also has become a synonym for abused technology unfortunately.
But MongoDB has not to be blamed for being abused and as long as MongoDB is used in cases for which it is meant to be used, everything is fine. Appropriate use cases are real documents. So whenever the requirement is:
  1. inconsistent data (storing the data as it was at that time, like documenting in its traditional meaning)
  2. ACID transaction for a single document
  3. very flexible object structure, which has to be changeable during runtime
The MongoDB installation on a Linux system is charming easy.
There are several gems for using MongoDB in a Ruby On Rails application under the hood. Mongoid is one of the recommended.
After adding it in the Gemfile:
gem 'mongoid'
a simple BirthCertificate model would look like:
class BirthCertificate
  include Mongoid::Document
  field :name
  field :date_of_birth, type: Date
end
Please note the model was not inherited from ActiveRecord::Base, but includes the Mongoid::Document, which makes it transact with MongoDB under the hood. Furthermore 2 fields were configured; name with the default String type and date_of_birth with Date type. Creating a new birth certificate in the Rails console:
BirthCertificate.create name: 'Robert Redford', 
  date_of_birth: Date.new(1936, 8, 18)
MongoDB also has a console for accessing the database (20150215_development). Starting it from bash:
mongo 20150215_development
and asking it for the created record (Attention, it is NoSQL!):
db.birth_certificates.find()
{
  "_id" : ObjectId("55281a5c616e740db0010000"), 
  "name" : "Robert Redford", 
  "date_of_birth" : ISODate("1936-08-18T00:00:00Z") 
}
If a further attribute had to be added, the class could be enhanced like:
class BirthCertificate
  include Mongoid::Document
  field :name
  field :date_of_birth, type: Date
  field :name_of_father
end
The new field name_of_father was introduced later for some reasons and creating a new birth certificate:
BirthCertificate.create name: 'Jennifer Shrader Lawrence', 
  date_of_birth: Date.new(1990, 8, 15), 
  name_of_father: 'Gary Lawrence'
Listing in MongoDB console again:
db.birth_certificates.find()
{ 
  "_id" : ObjectId("55281a5c616e740db0010000"), 
  "name" : "Robert Redford", 
  "date_of_birth" : ISODate("1936-08-18T00:00:00Z")
}
{
  "_id" : ObjectId("55281c4b616e740db0030000"), 
  "name" : "Jennifer Shrader Lawrence", 
  "date_of_birth" : ISODate("1990-08-15T00:00:00Z"), 
  "name_of_father" : "Gary Lawrence" 
}
makes the difference obvious. The older record has no name_of_father, which is important, because the old record should not be modified in any way. It is a document, which has to remain the same despite any structural evolution.
By the way, database migrations are lapsed for mongoid models.
There is way more to say about MongoDB and its features like aggregation and enterprise requirements like replication and sharding.
The flexibility is inviting, but please keep in mind, using MongoDB only makes sense, if inconistent data is wanted - the characteristic of real documents.

Supported by Ruby 2.2.1, Ruby on Rails 4.1.0 and MongoDB 3.0.2