DealTaker.com > Inside DealTaker > PHP & MongoDB Sitting in a Tree: Part 2

Inside DealTaker

PHP & MongoDB Sitting in a Tree: Part 2

June 22, 2010 ellisgl

In part II of this tutorial series, I’ll cover securing your MongoDB install and go over “Relations”. Before we start, if you have not, read part 1 first.

Security
So to make good on my promise, let’s get our MongoDB a little be more secure than what it is today. (*Note: At the time of this writting, MongoDB only supports a simplistic security method, username and password. No encryption, no login server integration, ect.)

First open up your shell/command line and bring up the MongoDB Client. In *NIX, execute “./mongo” or Windows, “mongo”. Of course you might need to navigate to the location where MongoDB was install and execute it from the “bin” path. In my setup I have to execute it from “C:wampbinmongomongodb-win32-x86_64-1.4.1bin”.

Now that you have the client up enter in the following commands:

[bash]
use admin
db.addUser(“admin”, “admin_password”)
db.auth(“admin”, “admin_password”)
[/bash]

What we have done here is created a DB named “admin”, added a user to that DB named “admin” with the password of “admin_password” (I wouldn’t use “admin_password” for my admin password if I were you), then we authenticated our newly created user. If you don’t authenticate after adding the user, you won’t be able to perform any actions. OK, now that we have that taken care of, let get on with “relations”.

Having relations

In MySQL, you might have laid out some tables using foreign keys to create 1:1, 1:N> and N:N relationships between them. So lets take simple 1:1 relationship table layout from MySQL, say “user” and “user_profile”, which the “user_profile” table will have primary key of “user_id”, which will be used also as a foreign key to create the relationship.

MySQL

[php]
<?php
// Connect to MySQL
$host = ‘localhost’;
$user = ‘root’;
$pass = “”;
$db = ‘testdb’;
$link = mysql_connect($host, $user, $pass, 1) or die(“Could not connect to: {$host}. Check your settings and try again.”);

// Drop DB if exsists first
$sql = sprintf(‘SET FOREIGN_KEY_CHECKS = 0;’);

mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);

$sql = sprintf(‘DROP DATABASE IF EXISTS `’.$db.’`;’);

mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);

// Create the DB
$sql = sprintf(‘CREATE DATABASE `’.$db.’`;’);

mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);

// Select the DB
mysql_select_db($db, $link);

// Create the “user” table
$sql = sprintf(‘CREATE TABLE `user`’.”n”.
‘ (`user_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,’.”n”.
‘ `username` VARCHAR (24)NOT NULL,’.”n”.
‘ `password` CHAR(32) NOT NULL,’.”n”.
‘ `email` VARCHAR(255)’.”n”.
‘ ) TYPE=innodb;’);

mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);

// Create the “user_profile” table
$sql = sprintf(‘CREATE TABLE `user_profile`’.”n”.
‘ (`user_id` INT UNSIGNED NOT NULL PRIMARY KEY,’.”n”.
‘ `aim` VARCHAR(24),’.”n”.
‘ `yahoo` VARCHAR(24),’.”n”.
‘ `icq` INT UNSIGNED,’.”n”.
‘ `likes` TEXT,’.”n”.
‘ `dislikes` TEXT’.”n”.
‘ ) TYPE=innodb;’);

mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);

// Create the Foreign Key
$sql = sprintf(‘ALTER TABLE `user_profile`’.”n”.
‘ADD CONSTRAINT `FK_user_profile_user_user_id`’.”n”.
‘FOREIGN KEY (`user_id`)’.”n”.
‘REFERENCES `user` (`user_id`);’);

mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);
[/php]

So now we have created a relationship between two tables in MySQL, lets insert a user.
MySQL

[php]
// Insert a user
$user = ‘jsmith’;
$pass = ’5f4dcc3b5aa765d61d8327deb882cf99′;
$eml = ‘jsmith@example.com’;

$sql = sprintf(‘INSERT INTO `user`’.”n”.
‘SET `username` = ‘%s’,’.”n”.
‘ `password` = ‘%s’,’.”n”.
‘ `email` = ‘%s’;',
mysql_real_escape_string($user),
mysql_real_escape_string($pass),
mysql_real_escape_string($eml));

mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);

// Get the ID of last insert
$id = mysql_insert_id($link);
[/php]

Now that we have a user, let’s insert the user’s profile data.
MySQL

[php]
// Add a profile for the last inserted user
$aim = ‘MrGoodGuy’;
$like = ‘Ice cream, Pizza and puppies’;
$dis = ‘Oil spills’;
$sql = sprintf(‘INSERT INTO `user_profile`’.”n”.
‘SET `user_id` = %u,’.”n”.
‘ `aim` = ‘%s’,’.”n”.
‘ `likes` = ‘%s’,’.”n”.
‘ `dislikes` = ‘%s’;',
$id,
mysql_real_escape_string($aim),
mysql_real_escape_string($like),
mysql_real_escape_string($dis));

mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);
[/php]

Now that we have some data in the profile table that relates to the first entry of the user, lets query both tables with an “INNER JOIN”.
MySQL

[php]
// Query both the “user” and “user_profile” tables with an “INNER JOIN”
$sql = sprintf(‘SELECT *’.”n”.
‘FROM `user` `u`’.”n”.
‘ INNER JOIN `user_profile` `p`’.”n”.
‘ ON `p`.`user_id` = `u`.`user_id`;’);

$qry = mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);
$cnt = mysql_num_rows($qry);

echo ‘All rows:<br/>’;

if($cnt > 0)
{
do
{
$row = mysql_fetch_assoc($qry);

echo ‘<pre>’;
print_r($row);
echo ‘</pre>’;
}while(–$cnt > 0);
}
[/php]

Enough of the MySQL example, we will be using document embedding to do the same thing in MongoDB.
MongoDB

[php]
<?php
// Connect to MongoDB
$user = ‘admin’;
$pass = ‘admin_password’;

try
{
$link = new Mongo();
$db = $link->admin;

$db->authenticate($user, $pass);
}
catch(MongoConnectionException $e)
{
die(‘Could not connect. Check to make sure MongoDB is running.’);
}

// Create and use the DB
$db = $link->testdb;

// Drop DB if exsists first
$db->drop();

// Create and use the DB
$db = $link->testdb;

// Create the “user” colection
$col = $db->user;

// Insert a new document
$doc = array(‘username’ => ‘jsmith’, ‘password’ => ‘ 5f4dcc3b5aa765d61d8327deb882cf99′, ‘email’ => ‘jsmith@example.com’,
‘profile’ => array(‘aim’ => ‘MrGoodGuy’, ‘likes’ => ‘Ice cream, Pizza and puppies’, ‘dislikes’ => ‘Oil spills’));

$col->insert($doc, true);

// Get the ID of last insert
$id = $doc['_id'];

// Get all documents
$res = $col->find();

echo ‘All documents:<br/>’;

foreach($res as $doc)
{
echo ‘<pre>’;
print_r($doc);
echo ‘</pre>’;
}
[/php]

“Wow, pretty simple!” is what I’m thinking you are saying to your self. With MongoDB, instead of having to create two tables, the FK, insert a record, get the id, and do another insert. We create the collection and just insert our data with a multidimensional associative array.


1:1 relationships are easy, but what about 1:N relationships? Let get back into MySQL mode.
MySQL

[php]
// Delete the “likes” and “dislikes” columns
$sql = sprintf(‘ALTER TABLE `user_profile`’.”n”.
‘DROP COLUMN `dislikes`,’.”n”.
‘DROP COLUMN `likes`;’);

$qry = mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);

// Create the “user_likes” table
$sql = sprintf(‘CREATE TABLE `user_likes`’.”n”.
‘ (`user_likes_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,’.”n”.
‘ `user_id` INT UNSIGNED NOT NULL,’.”n”.
‘ `likes` VARCHAR(255) NOT NULL’.”n”.
‘ ) TYPE=innodb;’);

$qry = mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);

// Create the Foreign Key
$sql = sprintf(‘ALTER TABLE `user_likes`’.”n”.
‘ADD CONSTRAINT `FK_user_likes_user_user_id`’.”n”.
‘FOREIGN KEY (`user_id`)’.”n”.
‘REFERENCES `user` (`user_id`);’);

// Create the “user_dislikes” table
$sql = sprintf(‘CREATE TABLE `user_dislikes`’.”n”.
‘ (`user_dislikes_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,’.”n”.
‘ `user_id` INT UNSIGNED NOT NULL,’.”n”.
‘ `dislikes` VARCHAR(255) NOT NULL’.”n”.
‘ ) TYPE=innodb;’);

$qry = mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);

// Create the Foreign Key
$sql = sprintf(‘ALTER TABLE `user_dislikes`’.”n”.
‘ADD CONSTRAINT `FK_user_likes_user_user_id`’.”n”.
‘FOREIGN KEY (`user_id`)’.”n”.
‘REFERENCES `user` (`user_id`);’);

$qry = mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);

// Insert some “likes” and “dislikes”
$like = array(‘Ice cream’, ‘Pizza’, ‘Puppies’);

foreach($like as $val)
{
$sql = sprintf(‘INSERT INTO `user_likes`’.”n”.
‘SET `user_id` = %u,’.”n”.
‘ `likes` = ‘%s’;',
$id,
mysql_real_escape_string($val));

$qry = mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);
}

$dis = array(‘Oil spills’);

foreach($dis as $val)
{
$sql = sprintf(‘INSERT INTO `user_dislikes`’.”n”.
‘SET `user_id` = %u,’.”n”.
‘ `dislikes` = ‘%s’;',
$id,
mysql_real_escape_string($val));

$qry = mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);
}

// Query the “user” table and pull in the “likes” and “dislikes” data.
$sql = sprintf(‘SELECT `u`.*,’.”n”.
‘ GROUP_CONCAT(DISTINCT `l`.`likes` SEPARATOR ‘, ‘) AS `likes`,’.”n”.
‘ GROUP_CONCAT(DISTINCT `d`.`dislikes` SEPARATOR ‘, ‘) AS `dislikes`’.”n”.
‘FROM `user` `u`’.”n”.
‘ INNER JOIN `user_likes` `l`’.”n”.
‘ ON `l`.`user_id` = `u`.`user_id`’.”n”.
‘ INNER JOIN `user_dislikes` `d`’.”n”.
‘ ON `d`.`user_id` = `u`.`user_id`’.”n”.
‘WHERE `u`.`user_id` = %u;’,
$id);

$qry = mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);
$cnt = mysql_num_rows($qry);

echo ‘All rows:<br/>’;

if($cnt > 0)
{
do
{
$row = mysql_fetch_assoc($qry);

echo ‘<pre>’;
print_r($row);
echo ‘</pre>’;
}while(–$cnt > 0);
}
[/php]

Boy is that a lot of work and I cheated with “group_concat” function. Let do this with MongoDB.
MongoDB

[php]
// Create a “1:N” for “likes” and “dislikes” in the “profile” element
$col->update(array(‘_id’ => $id), array(‘$set’ => array(‘profiles’ => array(‘likes’ => array(‘Ice cream’, ‘Pizza’, ‘Puppies’),
‘dislikes’ => array(‘Oil spills’)))));

echo ‘All documents:<br/>’;

// Get all documents
$res = $col->find();

foreach($res as $doc)
{
echo ‘<pre>’;
print_r($doc);
echo ‘</pre>’;
}
[/php]

Since MongoDB is schema-less, we can update how we store the “likes” and “dislikes” and it comes back to us as an array that we could iterate through. So what’s next?


N:N relationships. Oh boy are those the ultimate in a relational model. Once again, I’ll how we do this in MySQL.
MySQL

[php]
// Drop “user_likes” table if exsists first
$sql = sprintf(‘SET FOREIGN_KEY_CHECKS = 0;’);

mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);

$sql = sprintf(‘DROP TABLE IF EXISTS `user_likes`;’);

mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);

// Drop “dislikes” table if exsists first
$sql = sprintf(‘SET FOREIGN_KEY_CHECKS = 0;’);

mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);

$sql = sprintf(‘DROP TABLE IF EXISTS `user_dislikes`;’);

mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);

// Create the “likes” table
$sql = sprintf(‘CREATE TABLE `likes`’.”n”.
‘ (`likes_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,’.”n”.
‘ `likes` VARCHAR (255) NOT NULL’.”n”.
‘ ) TYPE=innodb;’);

mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);

// Create the “like” joins table
$sql = sprintf(‘CREATE TABLE `user_likes`’.”n”.
‘ (`user_id` INT UNSIGNED NOT NULL,’.”n”.
‘ `likes_id` INT UNSIGNED NOT NULL,’.”n”.
‘ PRIMARY KEY (`user_id`, `likes_id`)’.”n”.
‘ ) TYPE=innodb;’);

mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);

// Create Foriegn Keys
$sql = sprintf(‘ALTER TABLE `user_likes`’.”n”.
‘ADD CONSTRAINT `FK_user_likes_user_user_id`’.”n”.
‘FOREIGN KEY (`user_id`) REFERENCES `user` (`user_id`),’.”n”.
‘ADD CONSTRAINT `FK_user_likes_likes_likes_id`’.”n”.
‘FOREIGN KEY (`likes_id`) REFERENCES `likes` (`likes_id`);’);

mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);

// Insert some “likes”
$sql = sprintf(‘INSERT INTO `likes`’.”n”.
‘SET `likes` = ‘%s’;',
mysql_real_escape_string(‘Ice Cream’));

mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);

$sql = sprintf(‘INSERT INTO `%s`’.”n”.
‘SET `likes` = ‘%s’;',
mysql_real_escape_string(‘likes’),
mysql_real_escape_string(‘Pizza’)
);

mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);

$sql = sprintf(‘INSERT INTO `%s`’.”n”.
‘SET `likes` = ‘%s’;',
mysql_real_escape_string(‘likes’),
mysql_real_escape_string(‘Puppies’)
);

mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);

$sql = sprintf(‘INSERT INTO `likes`’.”n”.
‘SET `likes` = ‘%s’;',
mysql_real_escape_string(‘Kittens’));

mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);

// Create some “likes” relations (Cheating – since I already know the id’s)
$sql = sprintf(‘INSERT INTO `user_likes`’.”n”.
‘SET `user_id` = %u,’.”n”.
‘ `likes_id` = %u;’,
1,
1);

mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);

$sql = sprintf(‘INSERT INTO `user_likes`’.”n”.
‘SET `user_id` = %u,’.”n”.
‘ `likes_id` = %u;’,
1,
2);

mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);

$sql = sprintf(‘INSERT INTO `user_likes`’.”n”.
‘SET `user_id` = %u,’.”n”.
‘ `likes_id` = %u;’,
1,
3);

mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);

// Create the “dislikes” table
$sql = sprintf(‘CREATE TABLE `dislikes`’.”n”.
‘ (`dislikes_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,’.”n”.
‘ `dislikes` VARCHAR (255) NOT NULL’.”n”.
‘ ) TYPE=innodb;’);

mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);

// Create the “dislike” joins table
$sql = sprintf(‘CREATE TABLE `user_dislikes`’.”n”.
‘ (`user_id` INT UNSIGNED NOT NULL,’.”n”.
‘ `dislikes_id` INT UNSIGNED NOT NULL,’.”n”.
‘ PRIMARY KEY (`user_id`, `dislikes_id`)’.”n”.
‘ ) TYPE=innodb;’);

mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);

// Create Foriegn Keys
$sql = sprintf(‘ALTER TABLE `user_dislikes`’.”n”.
‘ADD CONSTRAINT `FK_user_dislikes_user_user_id`’.”n”.
‘FOREIGN KEY (`user_id`) REFERENCES `user` (`user_id`),’.”n”.
‘ADD CONSTRAINT `FK_user_dislikes_likes_likes_id`’.”n”.
‘FOREIGN KEY (`dislikes_id`) REFERENCES `dislikes` (`dislikes_id`);’);

mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);

// Insert some “dislikes”
$sql = sprintf(‘INSERT INTO `dislikes`’.”n”.
‘SET `dislikes` = ‘%s’;',
mysql_real_escape_string(‘Oil Spills’));

mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);

$sql = sprintf(‘INSERT INTO `dislikes`’.”n”.
‘SET `dislikes` = ‘%s’;',
mysql_real_escape_string(‘Screaming Babies’));

mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);

// Create some “dislikes” relations
$sql = sprintf(‘INSERT INTO `user_dislikes`’.”n”.
‘SET `user_id` = %u,’.”n”.
‘ `dislikes_id` = %u;’,
1,
1);

mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);

// Query “USER” and join with “likes” and “dislikes”
$sql = sprintf(‘SELECT `u`.*,’.”n”.
‘ GROUP_CONCAT(DISTINCT `l`.`likes` SEPARATOR ‘, ‘) AS `likes`,’.”n”.
‘ GROUP_CONCAT(DISTINCT `d`.`dislikes` SEPARATOR ‘, ‘) AS `dislikes`’.”n”.
‘FROM `user` `u`’.”n”.
‘ INNER JOIN `user_likes` `ul`’.”n”.
‘ ON `ul`.`user_id` = `u`.`user_id`’.”n”.
‘ INNER JOIN `likes` `l`’.”n”.
‘ ON `l`.`likes_id` = `ul`.`likes_id`’.”n”.
‘ INNER JOIN `user_dislikes` `ud`’.”n”.
‘ ON `ud`.`user_id` = `u`.`user_id`’.”n”.
‘ INNER JOIN `dislikes` `d`’.”n”.
‘ ON `d`.`dislikes_id` = `ud`.`dislikes_id`’.”n”.
‘WHERE `u`.`user_id` = 1;’);

$qry = mysql_query($sql, $link) or die(“<pre>SQL:n{$sql}nERROR:n”.mysql_error($link).’</pre>’);
$cnt = mysql_num_rows($qry);

echo ‘All rows:<br/>’;

if($cnt > 0)
{
do
{
$row = mysql_fetch_assoc($qry);

echo ‘<pre>’;
print_r($row);
echo ‘</pre>’;
}while(–$cnt > 0);
}
[/php]

Wow! Again, MySQL is making us work some more. With MongoDB we have three approaches. The first way is to fake it with a 1:1 or 1:N with an extra collection with the values you want to validate against. This might seem odd if you want to do a N:N relation, but there is reason why would want to do this in MongoDB . The second way is to create “manual relations”. This is kind of like MyISAM, where there isn’t an automatic relation, you have to specify it in your query. So lets look that one over.

MongoDB
[php]
// Create the “likes” and “dislikes” collections (create, drop and recreate).
$likes = $db->likes;
$likes->drop();
$likes = $db->likes;

$dis = $db->dislikes;
$dis->drop();
$dis = $db->dislikes;

// Insert some “likes” and “dislikes”
// “Likes”
$doc = array(‘likes’ => ‘Ice cream’);
$likes->insert($doc, true);

$doc = array(‘likes’ => ‘Pizza’);
$likes->insert($doc, true);

$doc = array(‘likes’ => ‘Puppies’);
$likes->insert($doc, true);

$doc = array(‘likes’ => ‘Kittens’);
$likes->insert($doc, true);

$ls = $likes->find();

// “Dislikes”
$doc = array(‘dislikes’ => ‘Oil spills’);
$dis->insert($doc, true);

$doc = array(‘dislikes’ => ‘Screeming children’);
$dis->insert($doc, true);

// Create a “N:N” for “likes” and “dislikes” in the “profile” element
// Find our “likes”
$ic = $likes->findOne(array(‘likes’ => ‘Ice cream’));
$pz = $likes->findOne(array(‘likes’ => ‘Pizza’));
$ps = $likes->findOne(array(‘likes’ => ‘Puppies’));

// Find our “dislikes”
// Find our “likes”
$os = $dis->findOne(array(‘dislikes’ => ‘Oil spills’));

// Create manual reference
$col->update(array(‘_id’ => $id), array(‘$set’ => array(‘profile’ => array(‘likes’ => array($ic['_id'], $pz['_id'], $ps['_id']),
‘dislikes’ => array($os['_id'])))));

// Get all documents
$res = $col->find();

foreach($res as $doc)
{
echo ‘<pre>’;
print_r($doc);

echo “nLikes:n”;

foreach($doc['profile']['likes'] as $key=>$val)
{
$l = $likes->findOne(array(‘_id’ => $val));
echo $l['likes'].”n”;
}

echo “nDislikes:n”;

foreach($doc['profile']['dislikes'] as $key=>$val)
{
$d = $dis->findOne(array(‘_id’ => $val));
echo $d['dislikes'].”n”;
}

echo ‘</pre>’;
}
[/php]

The thirday way is to create a reference (DBRef) to another document.
MongoDB

[php]
// Create an automatic reference
$col->update(array(‘_id’ => $id), array(‘$set’ => array(‘profile’ => array(‘likes’ => array(array(‘$ref’ => ‘likes’, ‘$id’ => $ic['_id']),
array(‘$ref’ => ‘likes’, ‘$id’ => $pz['_id']),
array(‘$ref’ => ‘likes’, ‘$id’ => $ps['_id'])
),
‘dislikes’ => array(array(‘$ref’ => ‘dislikes’, ‘$id’ => $os['_id']))))));

// Get all documents
$res = $col->find();

foreach($res as $doc)
{
echo ‘<pre>’;
print_r($doc);

echo “nLikes:n”;

foreach($doc['profile']['likes'] as $key=>$val)
{
$l = $likes->findOne(array(‘_id’ => $val['$id']));
echo $l['likes'].”n”;
}

echo “nDislikes:n”;

foreach($doc['profile']['dislikes'] as $key=>$val)
{
$d = $dis->findOne(array(‘_id’ => $val['$id']));
echo $d['dislikes'].”n”;
}

echo ‘</pre>’;
}
[/php]

So we’ve created an element that references a document. The key was to query what we needed, then used “$ref” identifier (More information) along with the ID return from our query to create the element. There is another way to do this in PHP by using the “MongoCollection::createDBRef” method.
MongoDB

[php]
$col->update(array(‘_id’ => $id), array(‘$set’ => array(‘profile’ => array(‘likes’ => array($likes->createDBRef($likes->findOne(array(‘likes’ => ‘Ice cream’))),
$likes->createDBRef($likes->findOne(array(‘likes’ => ‘Pizza’))),
$likes->createDBRef($likes->findOne(array(‘likes’ => ‘Puppies’)))
),
‘dislikes’ => array($dis->createDBRef($dis->findOne(array(‘dislikes’ => ‘Oil spills’))))));
[/php]

And we can also clean up our loop with less code:
MongoDB

[php]
foreach($doc['profile']['dislikes'] as $key=>$val)
{
$d = $col->getDBRef($val);
echo $d['dislikes'].”n”;
}
[/php]

Of course there is one problem with doing N:N in MongoDB . You can’t query it with a single query, since there is no “JOIN” support. So it would be better to embed the data you need to search on and return. Sure it might be redundant, but it seems that would be the best solution at this time. For more information about when to use DBRef vs Embedding, check out the Schema Design article.

Before we end this tutorial, let me leave you with a little extra, adding to the “likes” and “dislikes” in the “profile”:
MongoDB

[php]
// Add (Not replace) another “likes” and “Dislikes” to the profile.
$col->update(array(‘_id’ => $id), array(‘$pushAll’ => array(‘profile.likes’ => array($likes->createDBRef($likes->findOne(array(‘likes’ => ‘Kittens’)))),
‘profile.dislikes’ => array($dis->createDBRef($dis->findOne(array(‘dislikes’ => ‘Screeming children’)))))), array(‘safe’ => 1));

// Get all documents
$res = $col->find();

foreach($res as $doc)
{
echo “<pre>Pushed:n”;
print_r($doc);

echo “nLikes:n”;

foreach($doc['profile']['likes'] as $key=>$val)
{
$l = $col->getDBRef($val);
echo $l['likes'].”n”;
}

echo “nDislikes:n”;

foreach($doc['profile']['dislikes'] as $key=>$val)
{
$d = $col->getDBRef($val);
echo $d['dislikes'].”n”;
}

echo ‘</pre>’;
}
[/php]

You’ll notice that use used the “keyword” of “$pushAll” to push our array into the “likes” and “dislikes” element. Also note that we also used dot notation (“profile.likes”) to indicated that “likes” and “dislikes” are element of “profile”. So if we had something like “animal” which was an array element of “likes” which is part of “profile”, we would have done “profile.likes.animal”.

Until next time, when we will go over … I’m not sure yet, It’ll be a surprise … Happy Coding!

If you want a VPS with that has a “one-click” install of MongoDB, check out DreamHost. Also don’t forget to check out our tech blog and Computer related coupons.

Part 1

Post a New Comment

Comments and Reviews:

  1.  
    wow Thanks­ alot for writin­g this up :) But it'd better­ if u had some kind of syntax­ highli­ghting­ :(
  2.  
    Great, Thanks­ for your work!
  3.  
    Please­ reform­at your code snippe­ts with someth­ing. The articl­e is useful­, thank you very much for that, but readin­g the code with a propor­tional­ font and no indent­ation is painfu­l.
© 2012 DealTaker Inc., a Media General company. All Rights Reserved.

Coupons, Coupon Codes & Promotional Codes