Apresentação realizada no dia 8/11/2014 no evento TchêLinux Bento Gonçalves edição 2014 - http://bento.tchelinux.org
Falei sobre os conceitos de bases de dados NoSQL, cases, comparações com o modelo relacional, expressões SQL x MongoDB (orientado à documentos), instalação, recursos do MongoDB, operações via console, modelagem (abordagem embedded), driver PHP, anatomia do código PHP, CRUD (Create, Read, Update and Delete), ObjectId, operadores, segurança, persistência de objetos, tratamento de arrays (documentos aninhados), índices (performance), projeção, agregação, hospedagem, ferramentas de administração e programa de certificação.
2. Ari Stopassola Junior
Bacharel em Informática com ênfase em Análise de
Sistemas pela Unisinos, cursou mestrado em Engenharia
Informática e de Computadores pelo Instituto Superior
Técnico da Universidade Técnica de Lisboa (Portugal),
perito judicial 'ad hoc' especializado em TI (mantenedor do
site PERITO.inf.br), Zend Certified Engineer (PHP 5.3) e
Zend Certified PHP Engineer (PHP 5.5) #ZEND004019,
Certified ScrumMaster pela Scrum Alliance #203613,
Microsoft Certified Professional (MCP), consultor web e PHP
evangelist.
3. Roadmap
• Conceito de bases de
dados NoSQL
• cases
• comparações com o
modelo relacional
• expressões SQL x
MongoDB (orientado à
documentos)
• instalação
• recursos do MongoDB
• operações via console
• modelagem (embedded)
• driver PHP
• anatomia do código PHP
• CRUD (Create, Read,
Update and Delete)
• ObjectId
• operadores
• segurança
• persistência de objetos
• tratamento arrays
(documentos aninhados)
• índices (performance)
• projeção
• hospedagem
• ferramentas de
administração
• programa de certificação
4. NoSQL
• Not Only SQL (poderia ser NOSQL)
• Movimento de bancos de dados não
relacionais
• Também chamados: Modelo Relacional
Não Normalizado (MRNN)
• Seria mais apropriado dizer então “No
relational” pois alguns SGBDs possuem
interface SQL, embora sejam
categorizados como NoSQL. Ex.:
OrientDB
5. Taxonomia das bases NoSQL
• Documento (XML ou JSON)
– RavenDB, CouchDB, MongoDB
• Orientado a Objetos
– Db4o
• Chave/Valor (Key/Value)
– Redis, SimpleDB, Hbase, MemcacheDB, Riak, Berkeley DB
• Tabular (inspirado no BigTable do Google)
– Cassandra (Apache), Hypertable, Hbase
• Orientado a colunas (relacionais com características
NoSQL)
– Vertica, MonetDB, LucidDB, Infobright
• Grafos (Graph)
– Neo4j, OrientDB, Titan, DEX, InfiniteGraph, InfoGrid,
HyperGraphDB
• Outros
– Chordless, Mnesia Fonte: http://pt.wikipedia.org/wiki/NoSQL
6.
7. Quem usa NoSQL?
• eBay (pioneiro)
• New York Times
• Foursquare
• Electronic Arts
• GitHub
• SAP
• Disney
• Twitter
“Fifteen months ago, It took two weeks to perform
ALTER TABLE on the statuses [tweets] table.”
(setembro/2010)
Fonte: http://www.mongodb.org/about/production-deployments/
9. • Responsável por 438 casamentos ao dia nos
EUA
• Algoritmo “Compatibility Matching System”
reduz significativamente o número de
separações
• +51 milhões de usuários
• Processa 1 bilhão de combinações de casais
• Sob RDBMS demorava 2 semanas
processando
Fonte:
http://www.mongodb.com/press/mongodb-powers-critical-eharmony-compatibility-application-processing-1-billion-matches-dail-0
http://www.mongodb.com/presentations/big-dating-eharmony
10. Base orientada a documentos
Fonte: livro “MongoDB and PHP” de Steve Francia publicado pela O’Reilly
11. Por quê?
• Sistemas Orientados à Objetos
requer ORM (Object-Relational
Mapping)
• Normalização precisa de JOINs
• Complexidade dos relacionamentos
• Problemas ao escalar:
vertical versus horizontal
18. MongoDB
http://www.mongodb.org
• Nome vem da expressão huMONGOus
que significa “extremamente enorme”
• Banco de dados open source:
https://github.com/mongodb/
• Criado pela 10gen em C++, orientado a
documentos (formato JSON/BSON)
• Escalável
JavaScript Object Notation
• Schemaless (não há colunas ou tipos de
dados)
19.
20. Expressões SQL em
MongoDB
SQL MongoDB
Database Database
Table Collection
Index Index
Row Document
Column Field
Joining Embedding & linking
Partition Shard
Fonte: “Reference Cards for MongoDB”
21. Hierarquia
• Bancos de dados armazenam coleções
• Coleções possuem documentos
• No contexto PHP, documentos são arrays
multidimensionais
• Do ponto de vista do MongoDB, são
estruturas em JSON: Imagem extraída de: http://habrahabr.ru/post/156633
23. Instalação manual: OSX e Linux
1) Baixe o binário do MongoDB em http://www.mongodb.org/downloads
Descompacte o arquivo mongodb-osx-x86_64-2.x.x.tgz
2) Renomeie o diretório (resultado da descompactação) para um nome mais
apropriada. Ex.: mongodb
3) Abra o terminal e adicione ao final do arquivo /etc/paths o caminho:
sudo vim /etc/paths
Adicione a linha (de acordo com o diretório onde o MongoDB se encontra).
Ex.: /Users/ari/mongodb/bin
echo "export PATH=$PATH:/Users/ari/mongodb/bin" > ~/.bash_profile
4) Crie diretórios para armazenar as bases. O binário disponibilizado pela
10gen prevê que a base ficará na raiz do sistema operacional:
sudo mkdir -p /data/db/
sudo chown `id -u` /data/db
5) Inicie o serviço (deamon):
./mongod &
sudo ./mongod & (dependendo das permissões de usuário)
6) Abra a console do MongoDB e realize um teste:
mongo
> db.passeios.save( { a : 1 } )
> db.passeios.find()
Método alternativo ao passo 3
24. Instalação: Windows
• Download (certifique-se da arquitetura: 32 ou
64bit)
• Descomprimir no C:mongodb-win32-i386-2.x.x
• Renomear a pasta para C:mongodb
• Abra o terminal como usuário Administrador
• Crie o diretório c:datadb
cd ....
md data
md datadb
• Execute o deamon do MongoDB:
c:mongodbbinmongod.exe
• Em outra console execute o client:
c:mongodbbinmongo.exe
Fonte: http://docs.mongodb.org/manual/tutorial/install-mongodb-on-windows/
25. Driver para PHP
https://github.com/mongodb/mongo-php-driver
• Mantido por Derick Rethans (autor do
xDebug e vários outros projetos
significativos):
http://derickrethans.nl
• http://docs.mongodb.org/ecosystem/drivers/p
hp/
Foto: http://steve.maraspin.net/photo/gallery/conferences/2012-phpday-verona-italy/
26. Instalação do driver PHP para mongoDB
http://pecl.php.net/package/mongo
# sudo pecl install mongo
http://soupforthegirlysoul.blogspot.com.br/2012/03/sunday-smiles-optimism-opportunists-and.html
Adicione a linha extension=mongo.so no php.ini
29. Documentação antiga
• A partir da versão 1.3.0 do driver, Derick
Rethans mudou o nome da classe de
Mongo para MongoClient
• Mais detalhes no post institulado
“Mongo is dead, long live
MongoClient”:http://derickrethans.nl/mong
oclient.html
30. phpMoAdmin
1. Acesse:
http://www.phpmoadmin.com/
2. Faça o download do phpmoadmin.zip,
descomprima e copie o script
moadmin.php para a raiz do Apache –
coloque uma autenticação (caso deseje)
32. Conexão
//Conecta em localhost:27017
$conexao = new MongoClient();
//Conecta no host remoto na porta default
$conexao = new MongoClient("200.248.240.62");
//Host remoto na porta especificada
$conexao = new MongoClient("exemplo.com:65432");
$conexao = new MongoClient("localhost:27017",
array("username" => "root", "password" =>
"senha"));
34. Base de dados
$db = $conexao->nomebase;
//Formato alternativo
$db = $conexao->selectDB('nomebase');
ATENÇÃO: se a base não existir, ela será
criada, portanto certifique-se bem do nome da
base.
37. Inserção: documento dentro de
documento
$passeio = array(
"nome" => "Raízes Coloniais",
"valor" => 90,
"opcionais” => array("almoco" => true, "transfer" => true),
"observacoes" => "Senhor obeso, portanto reserve dois assentos",
"data" => new MongoDate()
);
db.passeios.insert({
"nome": "Itaimbezinho",
"valor": 120,
"opcionais": [
{
"almoco": false,
"transfer": true,
"observacoes": "Vai a família toda"
}
],
"observacoes": "já foi pago",
"data": new Date()
})
Sob o ponto de vista relacional,
não seria possível inserir um
array no campo “opcionais”.
Seria necessário uma nova
tabela (provavelmente até uma
terceira tabela, dependendo do
nível de normalização) para que
isso fosse viável – sendo
imprescindível o uso de JOINS
41. Consulta
//Busca TODOS
$elementos = $colecao->find();
foreach ($elementos as $objeto) {
echo $objeto['endereco']."n";
}
//Filtra por alguma característica
$elementos = $colecao->find(array('cidade' => 'Gramado'));
42. find versus findone
findone retorna um objeto do tipo MongoId
print_r($resultado);
http://php.net/manual/pt_BR/class.mongoid.php
find retorna um objeto do tipo MongoCursor
requer iteração
foreach($resultado as $item) {
print_r($item);
}
http://php.net/manual/pt_BR/class.mongocursor.php
43. ObjectId
(equivalente a PK)
• Cada documento (registro) recebe um
código único e imutável, chamado
ObjectId
• Esse identificador baseia-se no momento
em que a inserção foi realizada, em
conjunto com o nome do host,
concatenado ao PID (process ID) do
>s edbrv.pidaosrs eei ousm.f ninúdm()e[r0o] aleatório
> db.passeios.find()[0]._id
> db.passeios.find()[0]._id.getTimestamp()
ISODate("2013-06-07T20:07:26Z")
45. Como referenciar um ObjectId
> new ObjectId
ObjectId("51b278e1fc431ab4f7484cd7")
Atenção: ObjectId é um objeto e não uma
string
Como trabalhar esse ID numa URL? Ex.:
www.site.com.br/conteudo.php?id=51b278e1fc431ab4f748
4cd7
ou (via mod_rewrite)
46. Uso do $ nos operadores
✓
✗
$c->find(array('dist' => array('$lt' => 40)));
$c->find(array("dist" => array("$lt" => 40)));
Para mudar esse comportamento, edite a seguinte cláusula no php.mongo.cmd = ":"
$c->find(array("dist" => array(":lt" => 40)));
47. Segurança: SQL Injection
• SQL
– todas as operações (select, delete, drop
etc) são passadas ao banco de dados como
string, através do método query
– SQL aceita múltiplos comandos na mesma
requisição, delimitado por ponto-e-vírgula
• mongoDB
– cada operação tem um método distinto
48. • Cenário:
Request Injection
– http://url/script.php?usuario=ari
$c->find(array("usr" => $_GET['usuario']));
• Ataque:
– http://url/script.php?usuario[$ne]=ninja
– PHP converte automaticamente essa string num array:
$c->find(array("usr" => array('$ne'=>'ninja')));
• Resultado: busca todos os usuário exceto o
ninja (decorrente do operador $ne – not equal)
• Contra-medida
– faça casting para string através de serialize,
http_build_query, implode etc.
49. Persistência de Objeto
<?php
$conexao= new MongoClient();
$db = $conexao->agencia;
$passeio = new stdClass();
$passeio->nome = 'Tour Nova Petropolis';
$passeio->valor = 140;
$colecao = $db->passeios;
$colecao->insert($passeio);
$conexao = null;
?>
50. class Clientes{
public $nome;
public $trocas;
public function __construct($n, array $trocas){
$this->nome = $n;
$this->trocas = $trocas;
}
}
class Imoveis{
public $nome;
public $endereco;
public $reservado;
public function __construct($n, $e){
$this->nome = $n;
$this->endereco = $e;
$this->reservado = true;
}
}
class Trocas{
public $dia;
public $imovel;
public function __construct(DateTime $d, Imoveis $i){
$this->dia = $d;
$this->imovel = $i;
}
}
51. $imovel1 = new Imoveis("Cabana Carazal", "Estrada carazal, 3744");
$trocas[] = new Trocas(new DateTime, $imovel1);
$imovel2 = new Imoveis("Apto Vale do Bosque", "Condomínio vale");
$trocas[] = new Trocas(new DateTime, $imovel2);
$cliente = new Clientes("Ana Zago", $trocas);
$colecao->insert($cliente);
54. What’s happening?
• Não criamos a base de dados
• Não utilizamos as cláusulas SQL: CREATE
TABLE, auto_increment, PRIMARY
KEY, INDEX etc
• Não utilizamos ALTER TABLE para
adicionar novos campos
• Não foi necessário aplicar JOINS entre
entidades
• Nada de PDO, ORM ou bibliotecas externas
55. Teorema de Brewer
• Em 2000 Eric Brewer definiu a equação
CAP
• Só pode escolher DUAS (das três
• Consistência: clientes
disponíveis)
enxergam os dados de
forma idêntica
• Disponibilidade: toda
operação tem uma resposta
• Partição: sistema continua
operante mesmo
enfrentado particionamento
Fonte: http://dbpedias.com/wiki/NoSQL:Consistency_Models_in_Non-Relational_Databases
56. mongoDB é fully consistent
• Realiza operações atômicas no
documento
• Por natureza, dados são agrupados em
um único documento
• No entanto é suficiente e atende aos
requisitos ACID
• Base relacional requer transações (para
garantir ACID) pois representa os dados
em diferentes tabelas
57. Fire and forget it
ACID x BASE
• Inserção assíncrona – comportamento
padrão:
$colecao->insert($clientes);
–Não bloqueia o script enquanto a instrução
não tenha sido efetivada
–Melhora a performance da aplicação (não
a do banco)
• Inserção síncrona (modelo tradicional):
$colecao->insert($clientes,
array('safe'=>true));
– Aceito em insert, update, remove e save
58. Update
• Dois métodos
– Substituição (de tudo)
– Modificação (somente daquilo que se deseja)
59. ATENÇÃO: update por substituição
de array PHP pelo documento inteiro
Use
'$push'
60. Update in place
• Operador $set é atômico e mais eficiente, portanto evite a
$colecao->update(
array( '_id' => new MongoId('4fb69113550a6bdd02000000') ),
array( '$set' => array( 'UF' => 'Pernambuco', 'CEP' => '50710-090'))
);
Operador $set muda
ou adiciona elementos
$colecao->update(
array( '_id' => new MongoId('4fb69113550a6bdd02000000') ),
array( array( 'UF' => 'Pernambuco' , 'CEP' => '50710-090'))
);
Sobrescreve TODO o
documento
Diferente de (string)” 4fb69113550a6bdd02000000”
✓
✗
abordagem de manipular o array via PHP
• Primeiro parâmetro é o critério – nesse caso o ID do documento
62. Adicionando (append)
$colecao->update(
array( '_id' => new MongoId('4fb69113550a6bdd02000000') ),
array( '$push'=> array( 'proximo' => 'Academia de ginastica'))
);
63. Método save
• save é um wrapper para os métodos
insert e update
• Se passar um objeto _id ele edita o
registro através do update
• Caso não passe, ele insere como um
novo documento através do método
insert
70. Operadores de comparação
Operador Significado
$gt Greater than (maior que)
$gte Greater than equal (maior igual)
$in In (existe em)
$lt Less then (menor que)
$lte Less then equal (menor igual)
$ne Not equal (diferente)
$nin Not in (não existe em)
db.passeios.find({distancia: {$gte:100}})
71. Operadores de avaliação:
Expressões Regulares
$where = array('nome' => array(
'$regex' => new MongoRegex("/ari/i")));
$cursor = $colecao->find($where);
foreach($cursor as $item){
print_r($item);
}
Flag Significado
i case insensitive
m multiline
x can contain comments
l locale
s dotall, "." matches everything, including newlines
u match unicode
73. ALERTA: (Projeção)
$proj = array( "_id" => false,
"nome" => true,
"passeio" => true,
"rg" => false,
"datahora" => false);
Fatal error: Uncaught exception
'MongoCursorException' with message
'servidor:27017: Can't canonicalize
query: BadValue Projection cannot have a
mix of inclusion and exclusion.'…
O único campo que permite omitir é o _id
✗
Chave/Valos são considerados os mais rápidos e suportam mais carga de dados, pois trata-se de uma hash de chave que aponta para seu respectivo dado (que pode ser um objeto, string etc)
Documentos são mais sofisticados, pois podem possuir subdocumentos - o “expoente” é o MongoDB.Riak está sendo usado em 25% das empresas que figuram no Fortune 50 – ele é baseado no Dynamo (Amazon).Neo4j consegue armazenar 32 bilhões de nós.
No Brasil: CartolaFC, MTV
ACID: executa tudo ou nada (rollback), não permite que a base fique em estado inconsistente, uma transação não inferfere na outra e persiste fisicamente.
Integridade x tolerânciaConsistência x disponibilidadeEstratégia
Algoritmo “Compatibility Matching System”RDBMS é a sigla para Relational database management system”
Object-Relational Mapping gera overhead, exceto um CRUD (que é rápido).Escalabilidade depende diretamente da camada de persistência.Normalização é o processo de organização dos dados com o objetivo de minimizar a redundância, dependência e inconsistência
Normalização requer JOINS que, muitas vezes, são custosos (em termos de tempo de execução e recurso computacional)
Relacionamentos tornam difícil a escalabilidade horizontal
Em ambiente de cluster, transações em múltiplas tabelas tornam-se complexas
Escalabilidade vertical seria adicionar mais memória, expandir disco, substituir processador etc.
BSON: Binary-JSON - http://bsonspec.orgMongoDB é fully consistentAPI simples
Mantenedora
O comando: id –u (terminal do MacOSX) mostra o ID do usuário logado.
Talvez ele não encontre o executável, portanto execute ./mongod &Versões do MongoDB em 32-bit tem limite de dados em 2GB.A console do MongoDB é feita em JavaScript.
Para alterar a localização do banco, crie o diretório “data/db”: mkdir -p /Users/AriStopassolaJunior/mongodb/data/db
Baixe o monbodb.conf: https://github.com/mongodb/mongo/blob/master/rpm/mongod.conf
Altere as diretrizes dbpath, logpath e logappend (as três principais)Para testar se há outra instância do MongoDB rodando basta executar mongod –f /diretorio/monbod.conf
Possui drivers para 12 linguagens diferentes.
Lembre-se de reiniciar o servidor.
Ver “drivers” do MongoDB para diversas linguagens.
Análogo ao phpMyAdmin e phpPgAdmin
Ao acionar o client do MongoDB ele conecta-se automaticamente na base: testOutra forma de visualização (idêntica ao pretty) seria: db.passeios.find().forEach(printjson)
ObjectId é obrigatório e sempre retorna. Exit sai do terminal1 é ASC (ascendente)-1 é DESC (descendente)
Com senha
Se houver algum erro de conexão ou execução da uma query, será lançado um objeto MongoConnectionException (derivado da classe Exception, nativa do PHP), portanto se consegue manipular o erro utilizando um bloco try/catch.Para derrubar o banco, execute:use admindb.shutdownServer()
análoga a tabela em RDBMS
Documento dentro de documento.
No PHP usa-se instancia-se a classe MongoDate, enquanto que na console usa-se apenas Date()
Testei com insert e funciona igual.
Portanto seria desnecessário guardar, num campo específico, a data de criação do registro – pois essa informação já consta no ObjectIDPK é uma string ou integer
Experimente fazer um left outer join num ORM, ou uma função de agregação como média. Alguns falharam ao executar transações, passando a responsabilidade para a aplicação.Não há necessidade de cache, pois o mongoDB já fica em memório – o quanto houver de RAM disponível.Usar monboDB simplifica o desenvolvimento da aplicação pois não requer tratar de atualizações de registros, cache expirado etc.
É uma limitação do driver PHP para mongoDB
Usr._id mostra o ObjectId do documento na collection
Skip ele pula x elementos (semelhante ao OFFSET do SQL)Classe MongoCursorhttp://php.net/manual/pt_BR/class.mongocursor.php
Não basta apontar para a coleção (caso ainda não exista). É preciso adicionar algum item para que ela seja criada efetivamente:$colecao = $db->selectCollection('imoveis');
MongoDB é C e P
ACID é pessimista, forçando a consistência. BASE é otimista.Ao inserir o PHP não bloquei a execução aguardando um retorno do banco. Se for síncrono, espera até o banco se manifestar. "Safe" não significa consistência.Operações ficam bufferizadas
$set é chamado de operador “in place”Observe que $set NÃO é uma variável e sim um operador do MongoDB.
Upsert: se o critério não for satisfeito, um novo documento é criado com o critério.
Um append seria equivalente a um ALTER TABLE
mongoDB usa BTree
onde 1 ascendente e -1 descendente
Semelhante ao LIKE do SQL
Ou tudo true ou tudo false
Mensagem: “umongo.app” está danificado e não pode ser aberto. Você deve movê-lo para o Lixo.
Basta acessar: Preferências do Sistema -> Segurança e Privacidade -> aba Geral
Onde diz “Permitir aplicativos transferidos de:” marcar a opção “Qualquer lugar”.
Derrubando outro mito
Usa o software Remote Proctor Now: testa câmera, microfone e não permite que haja dois monitores acoplados no mesmo computador.