Tutorials
An introduction to PHP and Mongodb
Introduction
Most of us grew up on the concept of LAMP(Linux apache mysql and php) but there are times when that basic setup can become a real pain to maintain and scale. Generally the hardest part to scale out of a LAMP setup is MySQL. When running a large site with lots of data and traffic optimizing/scaling MySQL can be a really complicated undertaking.
That is where NoSQL comes into play. NoSQL is a very board term and some options are better than others. At the moment my choice for a NoSQL database is set firmly with MongoDB. Despite being a relatively new comer to the NoSQL scene MongoDB is quite mature and has awesome documentation.
Installation
If you are on a *nix platform you can simply use pecl
pecl install mongo
For windows you will need to download the MongoDB binaries [http://www.mongodb.org/downloads] and the php extensions [http://www.php.net/manual/en/mongo.installation.php#mongo.installation.windows]
Also don't forget to add the mongo extension to your php.ini
extension=mongo.so
Now that was easy wasn't it? That is almost always a good sign when the installation is a breeze
Basics
For those of us who only have experience with relational databases such as MySQL, Postgresql, etc understanding a Document Oriented database may be a bit difficult at first. Lets start by defining some of the key differences between relational sql databases and non-relational documented oriented databases
- Documents do not have a predefined schema like tables
- Joins are not natively supported but can be manually coded
Establishing a connection
Establishing a connection with mongo db is really easy
$mongo = new Mongo();
or you can define an address
$mongo = new Mongo('127.0.0.1:1234');
Now we must select a database to work with.
$db = $mongo->ebooks; //or we can also use $db = $mongo->selectDB('ebooks');
It is important to note that if the database does not already exist one will be created auto-magically.
Collections
Instead of using 'tables' like with a relational sql database we use 'Collections'. Simply put these are collections of documents. From a traditional sql developer standpoint these would be comparable to a database table(collection) and an entry within that table(document). However, this is much for flexible than that. Each document can have sub documents etc.
Creating or retrieving a collection:
$collection = $db->ebooks; //or like above $collection = $db->selectCollection('ebooks');
Just as above, if the collection does not exist one will be created. The max length of the collection name is 128 chars. Although, that includes the db name and indexes. So, it is generally better to stick with a name that is 80 or less chars in length.
Inserting documents
Inserting a document is really easy
$authors = $db->authors; $author = array( 'first_name'=>'Thomas', 'last_name' =>'Johnson', 'website'=>'http://www.tomfmason.net' ); $author_id = $authors->insert($author);
The return value of the insert is the object id. Also, you can pass an additional argument 'safe' which tells mongo to return immediately. This is much faster but you wont know immediately if the insert succeeded or not. That option would be really useful if you were inserting a large number of documents.
Querying documents
Lets say we have the following ebook documents in our ebooks collection.
$ebook = array( 'title'=>'An introduction to PHP and Mongodb', 'description'=>"Mongodb is an up and coming document oriented database that supports many awesome features including native PHP extension, an easy to use query interface and it is blazing fast. ", 'author_id'=>$author_id, 'reviews'=>array() ); $ebooks->insert($ebook);
and
$ebook = array( 'title'=>'php and mongo: A simple scalable CMS tutorial', 'description'=>"Some nice description here. ", 'author_id'=>$author_id, 'reviews'=>array() ); $ebooks->insert($ebook);
We can retrieve the author's ebooks like so
$filter = array( 'author_id'=>$author_id ); $my_ebooks = $ebooks->find($filter); foreach($my_ebooks as $book) { echo $book['title'] . "<br />"; echo $book['description'] . "<br />"; }
Something that caused me a bit of trouble was querying using an id. Lets say our author_id is a string like 4cffb213726e24640d000000. If you tried the following you would get back an empty result
$author_id = "4cffb213726e24640d000000" $filter = array('_id'=>$author_id); $author = $authors->findone($filter);
This is because in MongoDB the id's are not simply a string but an MongId object instead. You must do the following:
$author_id = new MongoId("4cffb213726e24640d000000"); $filter = array('_id'=>$author_id); $author = $authors->findone($filter);
Updating Documents
Now, lets say our author is wanting to update their website address. With MongoDB this is extremely simple.
$filter = array('_id'=>$author_id)); $update = array( '$set'=>array('website'=>'http://www.phpfreaks.com') ); $authors->update($filter,$update);
Lets say we are wanting to add a review for one of our ebooks. Would could do something like the following:
$filter = array('_id'=>$ebook_id); $review = array( 'name'=>'Thomas Johnson', 'email'=>'tomfmason@phpfreaks.com', 'website'=>'http://www.tomfmason.net', 'review'=>'MongoDB is awesomesauce' ); $update = array( '$push'=>array('reviews'=>$review) ); $ebooks->update($filter,$update);
Now our ebook should look something like:
Array ( [_id] => MongoId Object ( [$id] => 4cffb69f726e24d404000000 ) [author_id] => 4cffb213726e24640d000000 [description] => Mongodb is an up and coming document oriented database that supports many awesome features including native PHP extension, an easy to use query interface and it is blazing fast. [reviews] => Array ( [0] => Array ( [name] => Thomas Johnson [email] => tomfmason@phpfreaks.com [website] => http://www.tomfmason.net [review] => MongoDB is awesomesauce ) ) [title] => An introduction to php and mongo )
See the MongoDB Modifier Operations documentation [http://www.mongodb.org/display/DOCS/Updating#Updating-ModifierOperations] for more information on the modifiers such as $set, $unset,$push etc.
Deleting Documents
Deleting documents follows the same process as with querying and updating a document.
$filter = array('_id'=>$ebook_id); $ebooks->remove($filter,true);
GridFS
"The GridFS spec provides a mechanism for transparently dividing a large file among multiple documents. This allows us to efficiently store large objects, and in the case of especially large files, such as videos, permits range operations (e.g., fetching only the first N bytes of a file)."
In my opinion MongoDB's GridFS is one of the most exciting parts of MongoDB. The GridFS acts very much like a standard collection except it stores files. Here is a simple example:
$meta_data = array( 'name'=>"ebook.pdf", 'type'=>'ebook', 'description'=>'An awesome example ebook', 'ebook_id'=>'4cffb69f726e24d404000000', 'downloads'=>0 ); $grid = $db->getGridFS(); $file_id = $grid->storeFile(dirname ( __FILE__ ) . DIRECTORY_SEPARATOR . 'ebook.pdf',$meta_data);
If we were using php to upload this ebook we would use storeUpload [http://www.php.net/manual/en/mongogridfs.storeupload.php] instead. This makes storing php file uploads in MongoDB an absolute breeze.
We can now search the files just as we would with any other collection
$filter = array('_id'=>$file_id); $file_data = $grid->findone($filter); echo $file_data->file['description'];
Which should look something like this:
MongoGridFSFile Object ( [file] => Array ( [_id] => MongoId Object ( [$id] => 4cffd892726e24640d070000 ) [name] => ebook.pdf [type] => ebook [description] => An awesome example ebook [ebook_id] => 4cffb69f726e24d404000000 [downloads] => 0 [filename] =>/path/to/my/ebook.pdf [uploadDate] => MongoDate Object ( [sec] => 1291835538 [usec] => 0 ) [length] => 2622 [chunkSize] => 262144 [md5] => 64ab0b4bfe362d4c90647a03532e137a ) [gridfs:protected] => MongoGridFS Object ( [w] => 1 [wtimeout] => 10000 [chunks] => MongoCollection Object ( [w] => 1 [wtimeout] => 10000 ) [filesName:protected] => fs.files [chunksName:protected] => fs.chunks ) )
Conclusion
After getting a few private comments I thought I should come back and add a better conclusion. In short, I am very impressed with MongoDB and will use it when ever/where ever I can. However, we all need to keep in mind that not every tool is right for every job. If you require a highly reliable db, extremely fast reads/writes or are going to have very high update rates MongoDB is the perfect tool to solve those types of problems.