This presentation is an HTML5 website
Press → key to advance.
Zoom in/out: Ctrl or Command + +/-
This slide uses styles/codes from Google's slides for HTML5
César D. Rodas - crodas@php.net
PHPConference Brazil 2010
São Paulo - Brazil
These slides are Open Source (Apache License), feel free to reuse it as you wish.
// a document about me...
$crodas = array(
'_id' => 'py-4290392',
'name' => 'Cesar',
'surname' => 'Rodas',
'e-mail' => 'crodas@php.net',
'works' => array(
array('name' => 'PlumWillow', 'obj' => 'we are hiring'),
array('name' => 'Some open source projects', 'obj' => 'I like it!'),
)
);
// we save it
$db->users->save($crodas);
// we fetch it
$db->users->find(array('e-mail' => 'crodas@php.net'));
// or much better
$db->users->find(array('works.name' => 'PlumWillow'));
$user = array(
'name' => 'crodas',
'email' => 'crodas@php.net',
'website' => 'http://cesarodas.com',
);
$category = array(
'name' => 'Sport',
'description' => 'Everything about football (proper football)',
);
$comment = array(
'news' => $news['_id'],
'text' => 'I like MongoDB',
'user' => $user['_id'],
// duplicate properties from user object (to avoid joins)
'name' => $user['name'],
'website' => $user['website'],
);
$news = array(
'title' => 'My Talk about MongoDB',
'content' => 'MongoDB rules, I like it, bla, bla... ',
'author' => $user['_id'],
// duplicate name
'authorName' => $user['name'],
// copy all categories (entire structure) here
'categories' => array(
$category[1], $category[2]
),
// copy first 10 comments
// (suppose we show 10 first comments, then we paginate it)
'comments' => array(
$comment[0], $comment[1], $comment[2] .. $comment[9]
),
// comment users (reported by a dev at T!)
'commentsUsers' => array(
$userId => $userName
),
// we update this for every new comment
'totalComments' => $db->comments->count(array('news' => $news['_id'])),
);
SELECT news.*, user.name FROM news INNER JOIN user ON user.id = news.author id WHERE id = 1 SELECT category.category FROM category has news INNER JOIN category ON category WHERE news id = 1 SELECT * FROM comments INNER JOIN user ON user.id = comments.user id WHERE news id = 1
$mongo = new MongoDB;
$db = $mongo->database;
$news = $db->news->find(array('_id' => 1));
// Too bored to think in SQL right now
$query = array('totalComments' => array('$gt' => 10));
$news = $db->news->find($query)->sort(array('totalComments' => -1))->limit(5);
// Fetch news
$news = $db->news->findOne(array(
'_id' => $_POST['news_id'],
), array('totalComments' => true));
if (empty($news)) throw new Exception("News is not valid");
// Add new comment
$comment = array(
'user' => $_SESSION['user']['_id'],
'name' => $_SESSION['user']['name'],
'website' => $_SESSION['user']['website'],
'content' => $_POST['comment'],
);
$db->comment->save($comment);
// Update totalComments
$update = array('$inc' => array('totalComments' => 1));
if ($news['totalComments'] < 10) {
// save the name in a diff property to update it easily
$update['$set'] = array('commentUsers.' . $comment['user'] => $comment['name']);
// remove it to avoid du-du-duplicated values
unset($comment['user'], $comment['name']);
// cache the comments
$update['$push'] = array('comments' => $comment);
}
$db->news->update(array('_id' => $news['_id']), $update);
$update = array(
'$set' => array('name' => $new_name)
);
$option = array('multiple' => true);
// update in comments collection
$db->comments->update(array('user' => $user_id), $update, $option);
$update = array('$set' => array('authorName' => $new_name));
$db->news->update(array('author'd => $user_id), $update, $option));
// update name on cached comments
$update = array('$set' => array('commentUsers.' . $user_id => $new_name));
$db->news->update(array(), $update, $option));
// MongoDB (simple version – one node)
foreach ($db->news->find() as $news) {
$query = array('_id' => $news['_id']);
$update = array('$set' =>
array('url' => get_url_from_title($news['title']))
);
$db->news->update($query, $update);
}
// better approach (can run multiple instances safely)
while (true) {
$news = $db->command(array(
'findAndModify' => 'news',
// where url doesn't exists (much better than $exists => false)
'query' => array('url' => null),
// set a new value for url, diff than null
'update' => array('$set' => array('url' => ' ')),
));
if ($news['ok'] != 1) break;
$query = array('_id' => $news['value']['_id']):
$update = array('$set' =>
array('url' => get_url_from_title($news['value']['title']))
);
$db->news->update($query, $update);
}
$grid = $db->getGridFS();
$metadata = array(
"whatever" => "metadata",
"path" => "/foo",
"download" => 0
);
$grid->storeFile($filename, $metadata);
// or
$grid->storeBytes($bytes, $metadata);
// Or (save $ FILE['foo'])
$grid->storeUpload('foo', $metadata);
$grid = $db->getGridFS();
$file = $grid->findOne(array('path' => '/foo'));
// update download
$update = array('$inc' => array('download' => 1));
$id = array(' id' => $file->file[' id']);
$grid->update($id, $update);
// print it
echo $file->Bytes();
// or (a bit better)
$tmp = '/tmp/apache/' . $file->file[' id'];
if (!is_file($tmp)) $file->write($tmp);
virtual($tmp);
var map = function() {
if (!this.categories) {
return;
}
for (index in this.categories) {
// return (several times) a new document
// with id: category name, and value: 1
emit(this.categories[index].name, 1);
}
};
var reduce = function(key, values) {
var count = 0;
for (index in values) {
count += values[index];
}
return count;
};
// Shard key
{ x : 1}
// Targeted
db.foo.find( { x : 300 } )
db.foo.find( { x : 300, age : 40 } )
db.foo.insert( <object> )
db.foo.update( { x : 100 }, <object> )
db.foo.remove( { x : 100 } )
// Global
db.foo.find( { age : 40 } )
db.foo.find() // sequential
db.foo.find(...).sort( { age : 1 } )
db.foo.update( { age : 40 }, <object> )
db.foo.remove( { age : 40 } )
MongoDB = the future of web-development