Getting Started with MongoDB and PHP

Original author: Vikram Vaswani
  • Transfer
Generation Next
Over the past year, there has been a small revolution in the world of DBMSs associated with the advent of circuitless (structureless) DBMSs such as Apache CouchDB . These databases use a different approach than relational databases. They quickly become popular among Web developers because of their flexibility, simplicity and easy integration with modern technologies such as JSON.
This article provides a brief overview of MongoDB, one of the new generations of schematic-free DBMSs that has received a lot of attention from developers.

Start Me Up
On the official websiteMongoDB says that it is an extensible, high-performance, document-oriented open source database. There are a large number of platforms and is licensed under the GNU AGPL.
Although MongoDB is similar to CouchDB, there are major differences between them:
  • MongoDB developers should use native language drivers to access the database, while CouchDB uses REST
  • MongoDB supports more data types
  • MongoDB scalability is built on the basis of sharding technology ( there is no Russian analogue, left it in English ), while for CouchDB it is replication.
  • MongoDB queries use BSON objects , while CouchDB queries are generated using JavaScript.

The MongoDB documentation describes in detail all of these (and slightly more) differences, there are also tests comparing MongoDB, CouchDB and MySQL ( another reason for holy war ).
A quick look over, time to download and install MongoDB. In most cases, a standard binary package is enough; it contains MongoDB and a command-line client, a set of utilities for backup, recovery, as well as saving and receiving binary files. First, download the appropriate version for your system:
shell> cd / usr / local
shell> tar -xzvf mongodb-linux-i686-1.4.2.tgz
shell> ln -s mongodb-linux-i686-1.4.2 mongo
If you have Ubuntu, you can install MongoDB using aptitude. To do this, add the following line to /etc/apt/sources.list:
deb downloads.mongodb.org/distros/ubuntu 10.4 10gen
Then install this package using aptitude:
shell> aptitude update
shell> aptitude install mongodb-stable
When the package is installed, run MongoDB
shell server > mkdir / usr / local / mongo / data
shell> / usr / local / mongo / bin / mongod --dbpath = / usr / local / mongo / data


Note that by default, the MongoDB server considers that the data is stored in / data / db, and finishes execution if it does not find this path. The --dbpath option allows you to specify a different path.
You can use the command line to access the server, as shown below:
shell> / usr / local / mongo / mongo
Here's what it looks like:


You can issue commands to the server, just like in the MySQL client. Below is an example that shows the server version and available databases:
>show dbs
admin
local
>db.version()
1.4.2
>db.stats()
{
    "collections" : 0,
    "objects" : 0,
    "dataSize" : 0,
    "storageSize" : 0,
    "numExtents" : 0,
    "indexes" : 0,
    "indexSize" : 0,
    "ok" : 1
}

* This source code was highlighted with Source Code Highlighter.


Collecting Ideas
In the MongoDB universe, the equivalent of a table is “collection”. Just as tables have many records, collections have many “documents”. These documents are represented as JSON objects, with fields and values ​​representing key-value pairs, and stored (serialized) in BSON (Binary JSON) for storage. Below is an example of one such document:
{
"orderDate": "10-05-2010",
"orderTotal": 468.99,
}
Since the main element of MongoDB is a document in JSON format, and JSON supports hierarchical data, you can include one document in another . Further, since documents are serialized to BSON for storage, MongoDB can easily search for attached documents. Below is an example:
{
"orderDate": "10-05-2010",
“OrderTotal”: 468.99,
“shipTo”:
{
“street”: “17 Hill View”,
“zip”: “12345”,
“country”: “US”
}
}
To create a new MongoDB collection, run the client on the command line and run the following commands, which will create a collection called items "and add some documents:
  1. > db.items.insert({ name: 'eggs', quantity: 10, price: 1.50 })
  2. > db.items.insert({ name: 'bacon', quantity: 3, price: 3.50 })
  3. > db.items.insert({ name: 'tomatoes', quantity: 30, price: 0.50 })
* This source code was highlighted with Source Code Highlighter.

Continuing on, add more documents as shown above. To display the full list of documents in the collection, call the find () method with no arguments:
  1. > db.items.find({})
  2. { "_id" : ObjectId("4bea15293302000000006dcf"), "name" : "eggs", "quantity" : 10, "price" : 1.5 }
  3. { "_id" : ObjectId("4bea15463302000000006dd0"), "name" : "bacon", "quantity" : 3, "price" : 3.5 }
  4. { "_id" : ObjectId("4bea15523302000000006dd1"), "name" : "tomatoes", "quantity" : 30, "price" : 0.5
  5. }
* This source code was highlighted with Source Code Highlighter.

Note that each document has a special key '_id'. When you write a new document to the collection, MongoDB automatically adds a unique identifier to each document. This identifier can be used to obtain or modify a document, it is a kind of auto-increment key in relational databases.
To display a list of documents by any criterion, add this criterion (as a JSON object) to the find () method. Below is an example showing records with a quantity greater than 9 and a price less than 1:
  1. > db.items.find({quantity: {$gt: 9}, price: {$lt: 1}})
  2. { "_id" : ObjectId("4bea15523302000000006dd1"), "name" : "tomatoes", "quantity" : 30, "price" : 0.5
  3. }
  4.  
* This source code was highlighted with Source Code Highlighter.

Now let's try to write something in php!

Hooking Things Up
PHP MongoDB support is implemented through an extension that provides an API for accessing MongoDB collections. This extension is developed by Kristina Chodorow and is available for free on PECL under the Apache License. The extension is stable and allows you to perform most of the tasks related to accessing and using the MongoDB database from applications written in PHP.
To use this extension, install it using the standard command pecl
shell> pecl install mongo
Or you can download the source code, compile it into a PHP download module:
shell> tar -xzvf mongo-1.0.7.tar.gz
shell> cd mongo- 1.0.7
shell> phpize
shell> ./configure
shell> make
shell> make install
Now you have a downloadable PHP module called mongo.so, which is located in the standard directory for PHP modules. Connect this extension to php.ini, restart the Web server and check the activity of this extension with the phpinfo () command:


Now let's see what we can do using this extension
  1. try {
  2.  // open connection to MongoDB server
  3.  $conn = new Mongo('localhost');
  4.  
  5.  // access database
  6.  $db = $conn->test;
  7.  
  8.  // access collection
  9.  $collection = $db->items;
  10.  
  11.  // execute query
  12.  // retrieve all documents
  13.  $cursor = $collection->find();
  14.  
  15.  // iterate through the result set
  16.  // print each document
  17.  echo $cursor->count() . ' document(s) found.
    '; 
  18.  foreach ($cursor as $obj) {
  19.   echo 'Name: ' . $obj['name'] . '
    ';
  20.   echo 'Quantity: ' . $obj['quantity'] . '
    ';
  21.   echo 'Price: ' . $obj['price'] . '
    ';
  22.   echo '
    ';
  23.  }
  24.  
  25.  // disconnect from server
  26.  $conn->close();
  27. } catch (MongoConnectionException $e) {
  28.  die('Error connecting to MongoDB server');
  29. } catch (MongoException $e) {
  30.  die('Error: ' . $e->getMessage());
  31. }
  32. ?>
* This source code was highlighted with Source Code Highlighter.

At the beginning of this script, a new Mongo object is initialized, the constructor of which passes the information necessary to establish a connection to the MongoDB server (in the example, the host name). This object is used for all subsequent interactions with the MongoDB server.
The next step is to gain access to the database. This can be done using the selectDB () method or, more simply, using the magic call method, refer to the database as an object property. Once access to the database is obtained, it is not difficult to access the collection using the selectCollection () method or using the magic call method, referring to the collection as a property. Collections are represented as MongoCollection objects.
Each MongoCollection object has a find () method that can be used to execute queries. The method takes two arrays as arguments: an array of request parameters and an array of fields that should be obtained as a result of a response to the request. The return value is the cursor represented by an object of type MongoCursor object. The MongoCursor type implements the Iterator template, so it’s easy enough to run through the entire returned set using foreach (). The MongoCursor type contains a count () method that returns the number of records.
PHP extension Mongo supports the exception model implemented in PHP 5.x and defines 5 types of exceptions: MongoConnectionException for connection-related errors, MongoCursorException and MongoCursorTimeoutException for request-related errors; MongoGridFSException for file interaction errors; and MongoException for all other errors. In the previous example, it would be a good idea to wrap the code in a try / catch block.
Below is a sample output from the previous example:


Addition And Subtraction
Adding a new document to the collection is quite simple. See the following example:
try {
 // open connection to MongoDB server
 $conn = new Mongo('localhost');

 // access database
 $db = $conn->test;

 // access collection
 $collection = $db->items;

 // insert a new document
 $item = array(
  'name' => 'milk',
  'quantity' => 10,
  'price' => 2.50,
  'note' => 'skimmed and extra tasty'
 );
 $collection->insert($item);
 echo 'Inserted document with ID: ' . $item['_id'];
 
 // disconnect from server
 $conn->close();
} catch (MongoConnectionException $e) {
 die('Error connecting to MongoDB server');
} catch (MongoException $e) {
 die('Error: ' . $e->getMessage());
}
?>

* This source code was highlighted with Source Code Highlighter.

To add a new document to the collection, create a new array containing the key-value pair that you want to insert (the mechanism also supports nested arrays that are converted into embedded documents) and pass this array to the insert method of an object of type MongoCollection. This method will add the document to the collection and calculate the value '_id' (unique identifier of the document), which will be added to the original array. This identifier is represented by a special type of MongoId, which is a hexadecimal representation of the identifier. Therefore, you can easily get the document identifier without making an additional request.
Below is an example:


The document is removed from the collection by the remove () method, which takes an array of criteria as parameters and deletes all documents matching these criteria. Usually remove () returns a value of type Boolean (true or false); however, if you pass the special 'safe' argument as the second argument, you will get an array with a lot of information, including the number of deleted documents. Below is an example:
try {
 // open connection to MongoDB server
 $conn = new Mongo('localhost');

 // access database
 $db = $conn->test;

 // access collection
 $collection = $db->items;

 // remove a document
 $criteria = array(
  'name' => 'milk',
 );
 $r = $collection->remove($criteria, array('safe' => true));
 echo 'Removed ' . $r['n'] . ' document(s).';
 
 // disconnect from server
 $conn->close();
} catch (MongoConnectionException $e) {
 die('Error connecting to MongoDB server');
} catch (MongoException $e) {
 die('Error: ' . $e->getMessage());
}
?>

* This source code was highlighted with Source Code Highlighter.

It is also possible to delete a document using its identifier. However, the MongoId method object is passed to the remove () method, not the PHP string. Below is an example:
try {
 // open connection to MongoDB server
 $conn = new Mongo('localhost');

 // access database
 $db = $conn->test;

 // access collection
 $collection = $db->items;

 // remove a document by ID
 $criteria = array(
  '_id' => new MongoId('4bea96b400f4784c0a070000'),
 );
 $collection->remove($criteria);
 echo 'Removed document with ID: ' . $criteria['_id'];
 
 // disconnect from server
 $conn->close();
} catch (MongoConnectionException $e) {
 die('Error connecting to MongoDB server');
} catch (MongoException $e) {
 die('Error: ' . $e->getMessage());
}
?>

* This source code was highlighted with Source Code Highlighter.

The document is updated using the save () method, as shown below:
try {
 // open connection to MongoDB server
 $conn = new Mongo('localhost');

 // access database
 $db = $conn->test;

 // access collection
 $collection = $db->items;

 // retrieve existing document
 $criteria = array(
  'name' => 'eggs',
 );
 $doc = $collection->findOne($criteria);
 
 // update document with new values
 // save back to collection
 $doc['name'] = 'apples';
 $doc['quantity'] = 35;
 $doc['note'] = 'green apples taste sooooo good!';
 $collection->save($doc);
 
 // disconnect from server
 $conn->close();
} catch (MongoConnectionException $e) {
 die('Error connecting to MongoDB server');
} catch (MongoException $e) {
 die('Error: ' . $e->getMessage());
}
?>

* This source code was highlighted with Source Code Highlighter.

Note that if findOne () does not return anything, calling save () will add a new document.
Asking Questions
When it comes to query execution, MongoDB offers a fairly flexible toolkit. You have already seen the find () method, which returns a set of documents matching the search criteria. There is also a findOne () method that returns a single document. You can use many search criteria - just pass the array to find () or findOne () as search criteria, and MongoDB will apply all these criteria with the AND modifier.
Below is an example:
try {
 // open connection to MongoDB server
 $conn = new Mongo('localhost');

 // access database
 $db = $conn->test;

 // access collection
 $collection = $db->items;

 // formulate AND query
 $criteria = array(
  'quantity' => 30,
  'price' => 0.5
 );
 
 // retrieve only 'name' and 'price' keys
 $fields = array('name', 'price');
 
 // execute query
 $cursor = $collection->find($criteria, $fields);

 // iterate through the result set
 // print each document
 echo $cursor->count() . ' document(s) found.
'; 
 foreach ($cursor as $obj) {
  echo 'Name: ' . $obj['name'] . '
';
  echo 'Price: ' . $obj['price'] . '
';
  echo '
';
 }

 // disconnect from server
 $conn->close();
} catch (MongoConnectionException $e) {
 die('Error connecting to MongoDB server');
} catch (MongoException $e) {
 die('Error: ' . $e->getMessage());
}
?>

* This source code was highlighted with Source Code Highlighter.

MongoDB also supports a large number of conditional and logical operators for creating complex queries. Plus, support for regular expressions. Below is an example that displays all records with an amount between 10 and 50 and whose names end in 'es':
try {
 // open connection to MongoDB server
 $conn = new Mongo('localhost');

 // access database
 $db = $conn->test;

 // access collection
 $collection = $db->items;

 // formulate complex query
 $criteria = array(
  'quantity' => array(
    '$gt' => 10,
    '$lt' => 50
   ),
  'name' => new MongoRegex('/es$/i')
 );
 
 // execute query
 $cursor = $collection->find($criteria);

 // iterate through the result set
 // print each document
 echo $cursor->count() . ' document(s) found.
'; 
 foreach ($cursor as $obj) {
  echo 'Name: ' . $obj['name'] . '
';
  echo 'Quantity: ' . $obj['quantity'] . '
';
  echo 'Price: ' . $obj['price'] . '
';
  echo '
';
 }

 // disconnect from server
 $conn->close();
} catch (MongoConnectionException $e) {
 die('Error connecting to MongoDB server');
} catch (MongoException $e) {
 die('Error: ' . $e->getMessage());
}
?>

* This source code was highlighted with Source Code Highlighter.

How it will look:


You can also change the number of returned documents or sort them by the required key using the limit () and sort () methods. Below is an example:
try {
 // open connection to MongoDB server
 $conn = new Mongo('localhost');

 // access database
 $db = $conn->test;

 // access collection
 $collection = $db->items;

 // execute query
 // sort by price
 // limit to 3 documents
 $cursor = $collection->find();
 $cursor->sort(array('price' => 1))->limit(3);
 
 // iterate through the result set
 // print each document
 echo $cursor->count() . ' document(s) found.
'; 
 foreach ($cursor as $obj) {
  echo 'Name: ' . $obj['name'] . '
';
  echo 'Quantity: ' . $obj['quantity'] . '
';
  echo 'Price: ' . $obj['price'] . '
';
  echo '
';
 }

 // disconnect from server
 $conn->close();
} catch (MongoConnectionException $e) {
 die('Error connecting to MongoDB server');
} catch (MongoException $e) {
 die('Error: ' . $e->getMessage());
}
?>

* This source code was highlighted with Source Code Highlighter.

By the way, if you go to find out how MongoDB executes a query inside, you can use the explain () method of the MongoCursor object to "look inside" the query processing system, very similar to the MySQL EXPLAIN command. Below is an example and output result:
try {
 // open connection to MongoDB server
 $conn = new Mongo('localhost');

 // access database
 $db = $conn->test;

 // access collection
 $collection = $db->items;

 // execute and explain query
 $criteria = array(
  'quantity' => array(
    '$gt' => 10,
    '$lt' => 50
   ),
  'name' => new MongoRegex('/es$/i')
 );
 $cursor = $collection->find($criteria);
 $cursor->sort(array('price' => 1))->limit(3);
 print_r($cursor->explain());
 
 // disconnect from server
 $conn->close();
} catch (MongoConnectionException $e) {
 die('Error connecting to MongoDB server');
} catch (MongoException $e) {
 die('Error: ' . $e->getMessage());
}
?>

* This source code was highlighted with Source Code Highlighter.



Rank And File
In addition to documents, MongoDB also supports binary data. Binary data up to 4 MB can be saved in a regular document, and data (files) that are larger than this size can be saved using a little thing called GridFS .
GridFS is a specification for splitting and saving large files in MongoDB. Typically, GridFS uses two collections: the 'files' collection, which collects metadata about each file, and the 'chunks' collection, which stores data divided into chunks. Each file in the 'files' collection has a unique identifier, similar to the identifiers of other documents stored in MongoDB; this identifier can be used to retrieve or modify the file.

The MongoDB PECL extension provides a set of MongoGridFS classes that can be used to interact with files saved using GridFS. Each file is represented by an instance of the MongoGridFSFile class, and each MongoGridFS object provides methods for adding, deleting, and searching for these files.

For a better understanding, consider the following example, which illustrates the process of adding an image to MongoDB:
try {
 // open connection to MongoDB server
 $conn = new Mongo('localhost');

 // access database
 $db = $conn->test;

 // get GridFS files collection
 $gridfs = $db->getGridFS();
 
 // store file in collection
 $id = $gridfs->storeFile('/tmp/img_2312.jpg');
 echo 'Saved file with ID: ' . $id; 
 
 // disconnect from server
 $conn->close();
} catch (MongoConnectionException $e) {
 die('Error connecting to MongoDB server');
} catch (MongoException $e) {
 die('Error: ' . $e->getMessage());
}
?>

* This source code was highlighted with Source Code Highlighter.

At the beginning of the example, an instance of the MongoGridFS class is obtained using the getGridFS () method of the MongoDB class, and then the storeFile () method stores the file in MongoDB. If you run this example and then look at the contents of your database, you will see two new collections 'fs.files' and 'fs.chunks'. If you look a little deeper into the 'fs.files' collection, then you will see the file you added.
> show collections
fs.chunks
fs.files
items
system.indexes
> db.fs.files.find()
{ "_id" : ObjectId("4beaa34f00f4784c0a300000"), "filename" : "/tmp/img_2312.jpg", "uploadDate" : "Wed May 12 2010 18:17:11 GMT+0530 (India Standard Time)", "length" : 11618, "chunkSize" : 262144, "md5" : "e66b9a33c7081ae2e4fff4c37f1f756b" }

* This source code was highlighted with Source Code Highlighter.

As an alternative to the storeFile (), there is a storeUpload () method that is designed to be used in conjunction with file downloads using PHP. Using this feature is very easy: pass the name of the file upload field in the form to storeUpload, and MongoDB will do everything itself. You can also pass the file name as the second argument.
Below is a small example:

 
 
  

   Select file for upload:
   
      
  

     if (isset($_POST['submit'])) {
   try {
    // open connection to MongoDB server
    $conn = new Mongo('localhost');
   
    // access database
    $db = $conn->test;
   
    // get GridFS files collection
    $gridfs = $db->getGridFS();
    
    // check uploaded file
    // store uploaded file in collection and display ID
    if (is_uploaded_file($_FILES['f']['tmp_name'])) {
     $id = $gridfs->storeUpload('f');
     echo 'Saved file with ID: ' . $id;      
    } else {
     throw new Exception('Invalid file upload'); 
    }
        
    // disconnect from server
    $conn->close();
   } catch (MongoConnectionException $e) {
    die('Error connecting to MongoDB server');
   } catch (Exception $e) {
    die('Error: ' . $e->getMessage());
   }       
  }
  ?>
 


* This source code was highlighted with Source Code Highlighter.

Having a file in the database, how to get it back? Of course, using the document ID to get the file (MongoGridFS is the inheritor of MongoCollection, so you can use find () and findOne ()) as an object of the MongoGridFSFile class, and then write it to disk using the write () method, or output it to either using getBytes (). If you use the output in a browser, do not forget to add the necessary header (header)!
Below is an example:
try {
 // open connection to MongoDB server
 $conn = new Mongo('localhost');

 // access database
 $db = $conn->test;

 // get GridFS files collection
 $grid = $db->getGridFS();
 
 // retrieve file from collection
 $file = $grid->findOne(array('_id' => new MongoId('4beaa34f00f4784c0a300000')));
 
 // send headers and file data
 header('Content-Type: image/jpeg');
 echo $file->getBytes();
 exit; 
 
 // disconnect from server
 $conn->close();
} catch (MongoConnectionException $e) {
 die('Error connecting to MongoDB server');
} catch (MongoException $e) {
 die('Error: ' . $e->getMessage());
}
?>

* This source code was highlighted with Source Code Highlighter.


Boys And Their Toys
Although the PECL extension MongoDB offers quite convenient methods for working with MongoDB, you may need a higher level of abstraction - for example, if you are trying to integrate MongoDB into an existing application (framework-based application). In this case, you can use Morph , the "high-level library for MongoDB," which is available for free under the GNU GPL.

Morph is written as an ActiveRecord template that allows you to create a description of a MongoDB object, extending the main Morph_Object class. These instances of the Morph_Object class are reflected directly to MongoDB documents and have the same properties and methods that you can use to work using standard object notation.

To illustrate, suppose you want to create a toy database. Common attributes include name, description, description, age of the child, gender suitability, and price. You can represent all this information as an object of the Morph_Object class:
class Toy extends Morph_Object {
 
 public function __construct($id = null)
 {
  parent::__construct($id);
  $this->addProperty(new Morph_Property_String('name'))
     ->addProperty(new Morph_Property_String('colors'))
     ->addProperty(new Morph_Property_Integer('minAge'))
     ->addProperty(new Morph_Property_Integer('maxAge'))
     ->addProperty(new Morph_Property_Enum('gender', null, array('boys', 'girls', 'both')))
     ->addProperty(new Morph_Property_Float('price'));
 } 
}
?>

* This source code was highlighted with Source Code Highlighter.

Now you can create a new document using this template using the object of the Toy class, set the properties and write it using the save () method. Below is an example:
require_once 'Morph.phar';

// initialize MongoDB connection
$mongo = new Mongo('localhost');

// select database for storage
$storage = Morph_Storage::init($mongo->selectDb('test'));

// create object and set properties
$toy = new Toy();
$toy->name = 'Ride Along Fire Engine';
$toy->colors = 'red,yellow';
$toy->minAge = '2';
$toy->maxAge = '4';
$toy->gender = 'both';
$toy->price = 145.99;

// save to database
$storage->save($toy);
echo 'Document saved with ID: ' . $toy->id();
?>

* This source code was highlighted with Source Code Highlighter.

Also, you can get the object by identifier, update it and save it back.
require_once 'Morph.phar';

// initialize MongoDB connection
$mongo = new Mongo('localhost');

// select database for storage
$storage = Morph_Storage::init($mongo->selectDb('test'));

// create object and set properties
$toy = new Toy();
$toy->loadById('5421d0b9fc6217c5bb929baa14a97e08');
$toy->name = 'Jumping Squid';
$toy->colors = 'red,orange,green,blue,yellow';
$toy->minAge = '2';
$toy->maxAge = '10';
$toy->gender = 'boys';
$toy->price = 22.99;

// save to database
$storage->save($toy);
echo 'Document saved with ID: ' . $toy->id();
?>

* This source code was highlighted with Source Code Highlighter.


All these examples illustrate - MongoDB provides a reliable, feature-rich implementation of a schema-free DBMS. Accessibility across multiple platforms, easy integration with PHP and other languages, and extensive documentation (plus some very cool online experimentation options) make MongoDB ideal for developing a modern, document-oriented database.

Also popular now: