So I’ve decided that I want to properly document my MongoDB exploration and I may as well help others to learn with me.
Big disclaimer: I’m no MongoDB expert, I really am starting from scratch so if I get something wrong or you know of a better a way I’d love to hear from you =)
What I’m going to do here in part 1 is install MongoDB, install the PECL PHP extension and just play around a bit.
So lets get going.
Installing MongoDB
First we need to install Mongo (if you haven’t already). I’m working on a Ubuntu 9.04 server so I added the 10gen repository to my Aptitude repo list.
nano /etc/apt/sources.list
Add the following to a new line
deb http://downloads.mongodb.org/distros/ubuntu 9.4 10gen
(Take a look here to see some alternative Ubuntu + Debain sources http://www.mongodb.org/display/DOCS/Ubuntu+and+Debian+packages)
Save the file (Control + X)
Then run
apt-get update apt-get install mongodb-stable
Wait a few minutes and MongoDB is installed! For reference, the Mongo database path is located at /var/lib/mongodb/ and the configuration script is at /etc/mongodb.conf
Installing MongoDB PECL extension
Install the PHP developer package (if you haven’t already)
apt-get install php5-dev
Then run
pecl install mongo
Working directory setup
Set up your working directory and install the latest stable CodeIgniter snapshot
cd /public_html mkdir mongo101 cd mongo101 svn co http://svn.ellislab.com/CodeIgniter/trunk/ mv trunk/* ./ rm -r trunk
Lets go!
Open your favourite text editor (mine is Coda) and setup a new project etc etc.
Open /application/config/config.php and change the $config[‘base_url’] to wherever your install is.
Open /application/config/route.php and change the default controller to blog -$route[‘default_controller’] = “blog”;
Delete the welcome.php controller in the application/contollers folder
Delete the welcome.php view in the application/views folder
Create a new controller called blog.php
<?php class Blog extends Controller { function Blog() { parent::Controller(); } function index() { } }
In your index function write
function index() { // Connect to Mongo $connection = new Mongo('localhost:27017'); // Select a database $db = $connection->blog; // Select a collection $posts = $db->posts; }
Save the file and go to http://your-server/index.php/blog
If you’ve got a blank screen then it means you’ve successfully connected to Mongo, selected a database and selected a collection within the database.
Right, time for some concepts. So in Mongo a database is as it sounds, a database, and a collection is like a table in MySQL in that it holds rows (except rows are documents in Mongo terms). The PHP Mongo extension is to some extent an object relationship mapper which means we could have quite easily gone $posts = $connection->blog->posts instead.
Now that we’ve covered the basics and we know everything is working lets turn this into something a bit more useful.
Edit the Blog (constructor) function in your controller.
function Blog() { parent::Controller(); $this->load->helper('url');// Connect to Mongo $this->connection = new Mongo('localhost:27017');// Select a database $this->db = $this->connection->blog;// Select a collection $this->posts = $this->db->posts;}
Here we’re making the posts collection globally available so we don’t have to repeat ourselves in every function with the connection code.
Add a new function to your controller:
function add() { $data = array(); // If we've submitted the form... if($this->input->post('add')) { // Build the document $document = array( 'id' => ($this->posts->count() + 1), 'title' => $this->input->post('title'), 'body' => $this->input->post('body'), 'author' => $this->input->post('author'), 'date' => time() ); // Insert the document $this->posts->insert($document); $data['inserted'] = TRUE; } // Load the form $this->load->view('add', $data); }
When the form is submitted we build an array and then insert that into our collection. You’ll see to generate the ID we asked Mongo to return the number of existing documents in the collection and added one to it.
Create a new view file add.php
<!DOCTYPE html> <html> <head> <title>MongoDB 101 (Part 1)</title> </head> <body> <h1>Add a new post</h1> <?php if($inserted): ?> <p><strong>Post inserted successfully!</strong></p> <?php endif; ?> <form method="post"> <p> <label for="title">Title</label><br/> <input type="text" name="title" value="" /> </p> <p> <label for="body">Body</label><br/> <textarea name="body"></textarea> </p> <p> <label for="author">Author</label><br/> <input type="text" name="author" value="" /> </p> <p> <input type="submit" name="add" value="Add" /> </p> </form> <p><a href="<?php echo siteurl(array('blog', 'add')); ?>">Add a post</a></p> <p><a href="<?php echo siteurl(array('blog', 'index')); ?>">View all posts</a></p> </body> </html>
Now go to http://your-server/index.php/blog/add and you should be able to add a new post (you’ll see a success message if it worked). Just add the one post for now.
Add another function to your blog.php controller:
function view() { $this->load->helper('date'); $this->load->helper('typography'); // Load the document $document = $this->posts->findOne(); $data = array( 'title' => $document['title'], 'body' => $document['body'], 'author' => $document['author'], 'date' => $document['date'] ); $this->load->view('view', $data); }
What is happening here is we are asking Mongo to return just one document (which is returned as an array). We then pass this onto a new view.php file
<!DOCTYPE html> <html> <head> <title>MongoDB 101 (Part 1)</title> </head> <body> <h1><?php echo $title; ?></h1> <?php echo auto_typography( $body ); ?> <p><em>Posted by <?php echo $author; ?> on <?php echo unix_to_human( $date ); ?></em></p> <p><a href="<?php echo siteurl(array('blog', 'add')); ?>">Add a post</a></p> <p><a href="<?php echo siteurl(array('blog', 'index')); ?>">View all posts</a></p> </body> </html>
Now go to http://your-server/index.php/blog/view and you’ll see the post you just added.
Let’s adapt the view function so it can return a specific blog post.
function view() { $this->load->helper('date'); $this->load->helper('typography'); // Load the document $document = $this->posts->findOne(array('id' => (int)$this->uri->segment(3))); $data = array( 'id' => $document['id'], 'title' => $document['title'], 'body' => $document['body'], 'author' => $document['author'], 'date' => $document['date'] ); $this->load->view('view', $data); }
Here we added a query array into the findOne function. Note we typecasted the uri segment as an integer, this is because internally Mongo stores documents as BSON (binary JSON) and as our id field was is an integer we need make sure we’re being strict and querying it as an integer.
If you now go to http://your-server/index.php/blog/view/1 you should see your blog post.
To round this brief introduction to MongoDB off we’re going to edit the original index controller function to list the most recent five blog posts in date descending order.
function index() { $this->load->helper('date'); $this->load->helper('typography'); // Find 5 documents $documents = $this->posts->find()->limit(5); // Sort them by time descending $documents = $documents->sort(array('date' => -1)); $data = array( 'documents' => array() ); // While we have results while($documents->hasNext()) { // Get the next result $document = $documents->getNext(); $data['documents'][] = array( 'id' => $document['id'], 'title' => $document['title'], 'body' => $document['body'], 'author' => $document['author'], 'date' => $document['date'] ); } $this->load->view('index', $data); }
Some thing to note here, up until the point you start iterating over results (the while loop) you can play with the query to your hearts content. Also when you sort things, to sort ascending replace ASC with 1, and DESC with -1.
This is the index.php view file:
<!DOCTYPE html> <html> <head> <title>MongoDB 101 (Part 1)</title> </head> <body> <?php if(count($documents) > 0): foreach($documents as $document => $vars): ?> <h1><a href="<?php echo site_url(array('blog','view', $vars['id'])); ?>"><?php echo $vars['title']; ?></a></h1> <?php echo auto_typography( $vars['body'] ); ?> <p><em>Posted by <?php echo $vars['author']; ?> on <?php echo unix_to_human( $vars['date'] ); ?></em></p> <hr /> <?php endforeach; endif; ?> <p><a href="<?php echo site_url(array('blog', 'add')); ?>">Add a post</a></p> <p><a href="<?php echo site_url(array('blog', 'index')); ?>">View all posts</a></p> </body> </html>
Awesome
So to wrap-up we’ve installed MongoDB and the PHP extension for it. Then we’ve created a basic blog using the CodeIgniter work. Time for a beer!
For more information on the PHP Mongo functions see http://uk.php.net/manual/en/book.mongo.php
For more information on MongoDB see http://www.mongodb.org/
To download my code go to http://alexbilbie.com/mongo101.zip