Subscribe to PHP Freaks RSS

An introduction to PHP and Mongodb

Print
by Thomas Johnson on Dec 8, 2010 9:51:05 AM - 64,526 views

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 and the php extensions

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 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 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.

Comments

MichaƂ Jarosz Dec 9, 2010 4:55:17 AM

Sweet!
You beat me to writing a MongoDB tutorial :)

Thomas Johnson Dec 9, 2010 1:46:47 PM

Just in case anyone is interested I posted a blog showing an example usage of php and mongodb - http://www.tomfmason.net/blog/logging-apache-to-mongodb-in-php/

gizmola Jan 3, 2011 3:54:01 PM

Hey Tom,
Excellent intro to Mongo. I'm working on a project right now that uses Mongo, and it's a pretty slick database, with a focus on scalability that is pretty interesting. It's also worth saying that you interact with mongo using javascript format code, so if you're familiar with json format you'll find it pretty easy to understand.

One comment I have about your description of the _id is that in some cases making an id object doesn't work. I haven't really figured out what the issue is there, but I have some code where the _id is a number and making an id object out of it would not work with findOne. People might have to try it both ways I guess, or maybe if it's a string it has to be an object?

Thomas Johnson Jan 3, 2011 6:27:41 PM

@gizmola

I have yet to find a case where the id was an integer. Was the id assigned elsewhere or was that handled by mongo? So far everyone of my ids have been strings that are 24 characters in length with a random mix of letters and numbers. They look similar to a md5 checksum.

gizmola Jan 8, 2011 12:18:47 AM

@Tom
I didn't load the data in, so I'm not sure how it came to be that the id was string. Actually most of the data is numeric, but there are exceptions where the key will be something like '34-36' indicating it's a range. Pretty much that's all the collection has in it -- the _id and a description.

pastcow Apr 13, 2011 7:12:55 AM

Be sure to consult both of the following links, MongoDB despite not containing any SQL is still vulnerable to SQL injection.

http://php.net/manual/en/mongo.security.php

http://www.idontplaydarts.com/2010/07/mongodb-is-vulnerable-to-sql-injection-in-php-at-least/

gizmola Apr 13, 2011 3:17:01 PM

@Tom,
What I have found is that you can set the _id manually to be whatever you want it to be when you insert, and if you do that the usual rules don't apply.

lvgucci89 May 4, 2011 5:34:50 AM

good

thanyawzinmin Jul 6, 2011 4:27:02 AM

Thanks for sharing

tannu.mahadeshwar Sep 14, 2011 12:53:09 AM

Thanks for sharing

Add Comment

Login or register to post a comment.