Você está na página 1de 50

WORKSHOP ::: 1 PHP-DAY

MongoDB: alternativa intuitiva e no-relacional ao Mysql


Diego Sana

Sobre mim
Desenvolvedor e empreendedor web h 10 anos

Graduando em Cincia da Computao na UFES


1999: freemp3.com.br 2000: Central da Msica (.com.br)
Premiado pelo iBest em 2001 e 2003

2003: Primeiro contato com PHP 2004: Flogo.com.br (PHP, databases, escalabilidade) 2007: Power.com (idem) 2009: Restarting (bye-bye mysql, thanks for all the fish)

Blog: www.sanainside.com, Twitter: @sanainside

Sumrio
Bancos de dados relacionais e seus problemas

Bancos de dados no-relacionais (e o "movimento" NOSQL)


MongoDB: o que , quem faz, filosofia, funcionalidades, pros, contras, por que usar MongoDB: Botando a mo na massa MongoDB: indo alm

Motivao
Os bancos de dados relacionais se tornaram o "martelo" da indstria de armazenamento de dados Facilidade para entender o modelo relacional de dados e consult-los Versatilidade

Porm
Na computao, tudo que verstil demais, menos eficiente Bancos relacionais no "casam" com o paradigma OO. Necessidade de ORMs (O Vietn da Cincia da Computao) Concebidos no final da dcada de 70, quando no existia a ... WEB!!!

RDBMS e a web
RDBMS (como o mysql) so usados certamente em 99,9% dos sites 99,9% dos sites no precisam de boa parte de suas funcionalidades (ACID, triggers, stored procedures quem?) Apesar da versatilidade, no so to flexveis Pra escalar, s fazendo muita magia e rasgando o manual (foda-se normalizao, fodam-se chaves estrangeiras, fodam-se os joins)

Podemos fazer melhor: NoSQL


RDBMS sendo usados de forma no-relacional. Por que us-los ento? Engenheiros de grandes empresas da WEB desenvolveram suas prprias databases para resolver seus problemas de escala Algumas open-source, e as que no so foram "clonadas" por projetos Open-Source "Cool Kids" chamam esse "movimento" de NoSQL

Exemplos: BigTable
Usada internamente em vrios servios do Google Escalvel, tolerante a falhas e orientada colunas/linhas (hbrida) Disponvel para uso com Google App Engine Clones open-source: HBase e HyperTable

Exemplos: Dynamo
Criada pela Amazon.com Database chave / valor, alta escalabilidade / disponibilidade Disponvel para uso via Amazon Web Services ("SimpleDB") Clone Open-source: Project Voldemort (Linkedin)

Exemplos: Memcache
Projeto Open-Source iniciado por empresa contratada para desenvolver LiveJournal.com Na verdade um camada de cache chave/valor, alta escalabilidade/disponibilidade MemcacheDB = Memcache + BerkeleyDB = persistncia em disco Redis = Memcache no-voltil e com mais estruturas de dados (strings, listas, conjuntos)

Exemplos: CouchDB
Apache Foundation. Orientado a documentos, schema free Acesso via REST, documentos JSON ACID Querys precisam ser pr-definidas (criao de views)

O que todos eles tem em comum


Escalabilidade facilitada Alta-performance

Modelos de dados simplificados/limitados


Quase sempre querys simples, estilo "Select * from tabela where ID='xxx'"

Mongo DB: o melhor dos dois mundos


Um banco de dados de alta performance, escalvel, e schema-free orientado a documentos Em uso h quase 2 anos. Beta desde fev/2009. Verso 1.0 GA em agosto/2009 Preenche lacuna entre as databases do tipo Chave / Valor (rpidas e escalveis) e os tradicionais RDBMS (que tem mais funcionalidades)

Quem faz
Empresa americana 10gen, mesmo modelo da Mysql AB Fundadores trouxeram experincia adquirida na DoubleClick

Filosofia
Databases esto se especializando O modelo orientado a documentos de fcil implementao e gerenciamento, proporciona melhor performance Reduo de capacidades para maior performance importante, mas h necessidade de mais funcionalidades que as providas por databases chave/valor

Funcionalidades
Querys dinmicas e mais parecidas com SQL Suporte a ndices, inclusive em vetores Query profiling

Operadores $gt, $gte, $lt, $lte, $eq, $neq, $exists, $set, $mod, $where, $in, $inc, $pull, $push, $pop, $pushAll, $popAll

Funcionalidades
Manipulao server-side de dados usando Javascript GridFS para armazenamento eficiente de arquivos binrios grandes Escalabilidade via: replicao e auto-sharding (alpha) Suporte a falhas: replicao master-master

Pros
Alta performance (inserts/updates muito rpidos) Excelente cache (pode eventualmente dispensar Memcache) Escalabilidade (jura!?) Documentos armazenados so objetos/Json/Whatever (die ORM!!!) Schema-less = no precisa parar o site para adicionar uma nova coluna na tabela

Contras
Schema-less usa mais espao em disco Databases limitadas a 2GB em sistemas 32 bit (ilimitadas em 64bit) Crash-recovery no automtico Apesar de estvel e em uso por grandes sites, bugs ainda so frequentes (principalmente nos drivers)

Adequado para
Aplicaes web em geral que demandem boa performance de inserts/updates/reads Armazenar dados de grande volume, baixo valor. Logging / Analytics em Tempo Real Armazenar diretamente objetos ou dados em Json (por ex: como os obtidos de APIs)

Inadequado para
Sistemas altamente transacionais (Mongo no garante atomicidade em transaes) Problemas que necessitem de querys SQL complexas Business Intelligence

Ei, mais eu s quero fazer o site da padaria do meu tio!!!


Mysql ou outro RDBMS atende plenamente Ainda assim existem bons motivos para usar MongoDB:
Facilidade de lidar com os objetos Melhor performance legal conhecer e implementar novas tecnologias

Modelo de dados
Databases Colees Documentos

BSON

Databases
Agrupamento fsico de colees Um arquivo de namespaces (nomes de colees e ndices) Arquivos de dados (pr-alocao: 64 MB -> 128MB -> 256MB -> 512 MB -> 1GB -> 2GB -> 2GB...) 10k colees/databases (limite configurvel)

Colees
Agrupamento lgico de documentos em uma database (equivale s tabelas do RDBMs) Schema-free Nmero ilimitado de documentos

Documentos
Unidade de armazenamento (equivale s linhas do RDBMs) Todos devem ter um _id nico (em relao coleo) Tamanho mximo de 4MB (para objetos maiores, use GridFS)

BSON
Formato de armazenamento de dados de documentos ou objetos no MongoDB "Binary JSON" Permite representao de algumas formas de dados que no fazem parte do padro JSON (Date / BinData, por exemplo)

Baixando o MongoDB
Binrios disponveis em 32/64 bit para Linux, Windows, OS X e Solaris Verso 32 bit linux: http://downloads.mongodb.org/linux/mongodblinux-i686-1.0.0.tgz Demais verses direto em http://www.mongodb.org/display/DOCS/Downloa ds

Instalao do Servidor MongoDB


Extrair contedo do arquivo mongodb-linux-i6861.0.0.tgz para pasta /mongodb Crie pasta /data/db e marque com permisso de escrita para o usurio desejado Execute o daemon: /mongodb/bin/mongod run

Alternativa: usar um init script


Scripts para Ubuntu e Centos em www.sanainside.com/wpcontent/uploads/2009/09/initscripts-mongodb.zip

Instalao do Driver PHP


Via pecl: pecl install mongo channel://pecl.php.net/mongo-0.9.5 Via GitHub: baixar source de http://github.com/mongodb/mongo-phpdriver/tarball/master
Extrair contedo de tar.gz Acessar pasta e digitar no console: $ phpize $ ./configure $ sudo make install

Ao final, adicionar essa linha ao php.ini: extension=mongo.so Reiniciar apache

Incluso com MongoDB


Shell : /mongodb/bin/mongo Interface web: http://localhost:28017 Ferramentas para importar / exportar / backup / restore: [/mongodb/bin/] mongoimportjson, mongoexport, mongodump, mongorestore

Usando MongoDB com PHP


Abrir conexo:
$conn_mongodb = new Mongo(); // Assume mongod rodando em localhost:27017 (default)

Por padro, no h usurios nem senhas. Configure seu firewall (como iptables) para no deixar a porta exposta para ips indesejados possvel adicionar autenticao individual para cada database, inserindo usurio/senha na coleo "admin".

Alguns mtodos bsicos


$db = $conn_mongodb->selectDB("nomedadatabase"); $col = $db->selectCollection("nomedacolecao");

$col->insert($doc);
$col->save($doc); $cursor = $col->find($id); $cursor->getNext();

Implementando um MongoLog
Vamos implementar funes CRUD de um sistema de blogging com:
Multi-usurios Posts Comentrios Tags Contador de Visitas Lista de amigos

Modelagem
Database: blog Colees: users, posts, friends Cada documento da coleo posts conter no s os textos de um post, como tambm os comentrios, as tags e o contador de visitas (embed documents)

Criando e inserindo na coleo "users"


No necessrio criar database/coleo previamente Um documento da coleo usurio:
$doc = array("_id" => 1, "email" => "meu@email.com", "nome" => "Joaozinho", "nivel" => "admin_supremo");

Pra inserir:
$conn_mongodb->selectDB("blogs")->selectCollection("users")->save($doc);

Se seu documento no tiver um "_id", mongodb ir atribuir um MongoID automaticamente (12 bytes)

Fazendo uma consulta


Assim como documentos, querys tambm so especificadas como array Retornar todos os campos de todos usurios com nome Joaozinho:
$query = array("nome" => "Joaozinho"); $cursor = $conn_mongodb->selectDB("blogs")->selectCollection("users") ->find($query)

Retornar o email dos usurios com nome Joaozinho


$query = array("nome" => "Joaozinho"); $fields = array("email" => true); $cursor = $conn_mongodb->selectDB("blogs")->selectCollection("users") ->find($query,$fields);

find() vs findOne()
find() retorna cursor para resultados encontrados:
$query = array(_id => 1); $col = $conn_mongodb->selectDB("blogs")->selectCollection("users"); $cursor = $col->find($query); while($cursor->hasNext()) { $doc = $cursor->getNext(); }

findOne() retorna o documento (apenas um)


$query = array(_id => 1); $col = $conn_mongodb->selectDB("blogs")->selectCollection("users"); $doc = $col->findOne($query);

find(), sem parametros, retorna cursor p/ todos docs

Inserindo um post
Inicialmente o documento precisa conter apenas os campos do post
$doc = array(titulo => Titulo do meu post, texto => Aqui vai meu textculo, data => new MongoDate(), idAutor => 1)); $col->insert($doc);

Ao fazer insert(), driver atribui MongoID em $doc[_id] Update para inserir tags. Dois mtodos:
// mtodo portugus: adiciona tags ao array $doc e o salva no db: $doc[tags] = array(teste,mongodb); $col->save($doc) // mtodo l337: usando o modificador $set $query = array(_id => $doc[_id]); $updatefields = array($set => array(tags => array(teste,mongodb))); $col->update($query,$updatefields,true);

Inserindo comentrios num post


Assim como tags, comentrios tambm sero inseridos no documento do post, como um vetor de comentrios Usaremos o modificador $push, que permite inserir novos valores em um array sem necessidade de fornecer o array na query

$comentario = array(nome => Comentador, email => me@obriga.com comentario => Que legal);
$query = array(_id => $doc[_id]); $updatefields = array($push => array(comentarios => $comentario)); $col->update($query,$updatefields,true); Parametro 3 em update() aceita os valores true ou false (bool), e determina que, caso no exista o documento com o _id passado no parametro 1, ou o campo passado no parametro 2, Mongo faa a criao

Contador de Visitas
Visitas sero contadas em um campo no documento de posts Usaremos o modificar $inc, que permite incrementar o valor de um campo
$query = array(_id => $doc[_id]); $updatefields = array($inc => array(visitas => 1)); $col->update($query,$updatefields,true);

No exemplo acima, fizemos um incremento de +1 no campo visitas. Para fazer um incremento de +2, usaramos:
$updatefields = array($inc => array(visitas => 2));

Lista de amigos
Uma lista de amigos de um usurio pode ser um documento cujo _id seja o _id dele na coleo users e com um campo ids contendo um array de _id de seus amigos Usaremos o modificador $push, assim como fizemos nos comentrios:
$col = $db->selectCollection(friends); $idUser = 1; $idFriend = 2; $query = array(_id => $idUser); $updatefields = array($push => array(ids => $idFriend)); $col->update($query,$updatefields,true);

Em vetores numricos, podemos usar o modificador $pull para excluir um valor:


$query = array(_id => 1); $updatefields = array($pull => array(ids => 2)); $col->update($query,$updatefields);

Contador, paginao e ordenao


Contar o nmero de posts
$col = $db->selectCollection(posts); $contador = $col->count();

Obter todos os posts em ordem cronolgica


$col = $db->selectCollection(posts); $cursor = $col->find(); $cursor_ascendente = $cursor->sort(array(data => 1)); $cursor_descendente = $cursor->sort(array(data => -1));

Obter um post, pulando os dois primeiros


$cursor = $col->find(); $cursor->sort(array(data => -1)); $cursor->skip(2); $cursor->limit(1);

Querys usando operadores


Obter posts com mais de 2 visitas:
$col = $db->selectCollection(posts); $query = array(visitas => array($gt => 2)) $cursor = $col->find($query);

Obter todos os posts sem comentrios


$col = $db->selectCollection(posts); $query = array(comentarios => array($exists => false)) $cursor = $col->find($query);

Obter todos os posts com a tag mongo


$col = $db->selectCollection(posts); $query = array(tags => array($in => mongo)) $cursor = $col->find($query);

Querys usando operadores


Obter posts contendo entre 1 e 3 visitas:
$col = $db->selectCollection(posts); $query = array(visitas => array($gt => 1, $lt => 3)) $cursor = $col->find($query);

Obter todos os posts com 2 comentrios


$col = $db->selectCollection(posts); $query = array(comentarios => array($size => 2)) $cursor = $col->find($query);

Obter posts com uma das tags: teste, mongo, php


$col = $db->selectCollection(posts); $query = array(tags => array($in => array(mongo, teste, php)) $cursor = $col->find($query);

ndices
A query anterior pode ser otimizada adicionado um ndice ao campo tags:
$col = $db->selectCollection(posts); $col->ensureIndex(tags);

Em campos em que a ordem importa, pode-se determinar a mesma num ndice:


$col = $db->selectCollection(posts); $col->ensureIndex(array(data => 1)); // ndice com ordem crescente $col->ensureIndex(array(data => -1)); // ndice com ordem decrescente

Para saber se uma query est usando ndices, use explain:


$query = array(tags => mongodb); $cursor = $col->find($query); var_dump($cursor->explain());

Outras querys: remoo


Remover um usurio da coleo users
$col = $db->selectCollection(users); $query = array(nome => Joaozinho); $col->remove($query);

Remover todos os usurios


$col->remove();

Remove uma coleo:


$db->dropCollection(users);

Remove uma database:


$db->drop();

Outras querys: Erros


No MongoDB, operaes de escrita (insert / update / delete) no bloqueam (fire and forget) e sempre retornam true. Para verificar se uma operao deu erro, deve-se usar mtodo lastError()
$doc = array(_id => 1); $col = $db->selectCollection(error); $col->insert($doc); if($error = $conn_mongodb->lastError()) { echo "Error: "; var_dump($error); }

Indo alm
No momento, mongodb s pode em hosts dedicados / VPS Desenvolvedores esto propondo suporte em hosts compartilhados Documentao da extenso mongophp: www.php.net/mongodb Documentao oficial bem completa: www.mongodb.com Lista de discusso com participao ativa e prestativa dos desenvolvedores: http://groups.google.com/group/mongodb-user

Perguntas?

Você também pode gostar