O foco principal dos bancos NoSQL atuais é a orientação a documentos, uma variação hash da orientação a objetos e alternativa aos RDBMSs, que dominaram a orientação dos gerenciadores de banco de dados por décadas.
O principal banco NoSQL é o CouchDB, DBMS do Projeto Apache baseado em Erlang, porém há uma alternativa bem mais simples e aparentemente tão poderosa quanto: MongoDB.
MongoDB combina os melhores funcionalidades de orientação a documentos, hashes e RDBMSs. É um banco de dados orientado a documentos, escalável, livre de esquema, de alto desempenho e código aberto escrito em C++.
Este artigo dá continuidade ao artigo nas Reflexões de Monte Gasppa e Giulia C. sobre a instalação do MongoDB. Aqui você poderá ver um pouquinho do uso de um banco de dados orientado a documentos.
Este artigo é baseado na documentação oficial e entende que você instalou o MongoDB segundo descrito nas Reflexões de Monte Gasppa e Giulia C..
Conexão na base de dados
Para conectar na base basta usar o comando
mongo
:bash$ mongo
MongoDB shell version: 1.2.2
url: test
connecting to: test
type "help" for help
>
Caso você tenha configurado uma porta alternativa em
/srv/mongodb/etc/mongodb.conf
, você pode especificar isso na linha de comando do cliente:bash$ mongo --port 27018
Você também pode se conectar a um servidor remoto, caso ele esteja habilitado para conexão externa, usando a flag
--host
.Para escolher qual base de dados usar, o comando é
use
:> use mydb
Autorização
Você pode se autorizar na linha de comando com as opções
-u
(usuário) e -p
(senha), ou já do prompt do interpretador:> use admin
> db.auth('admin', 'ra35EG/dz');
Comandos básicos
A linguagem de interação com MongoDB é Javascript, mas há alguns comandos úteis no interpretador.
Para listar comandos úteis:
> help
Listar recursos uteis da base atual:
> db.help();
Listar recursos uteis de uma coleção (levemente equivalente a tabela de um banco relacional), no exemplo
foo
:> db.foo.help();
Para listar as bases instaladas:
> show dbs
Para listar as coleções da base atual:
> show collections
Listar usuários da base atual:
> show users
Criar usuário na base atual:
> db.addUser('admin', 'ra35EG/dz');
Autenticar-se:
> db.auth('admin', 'ra35EG/dz');
Listar o conteúdo de uma coleção:
> db.foo.find();
Apagar uma coleção:
> db.foo.drop();
Apagar a base de dados atual:
> db.dropDatabase();
Armazenamento de dados
Repare que o MongoDB é livre de esquema, portanto uma coleção pode conter estruturas de dados radicalmente diferentes, sempre no formato JSON.
Por exemplo, vamos inserir dois dados distintos na coleção
foo
da base mydb
:> use mydb
> var j = { name: 'mongo' };
> var t = { x: 3 };
> db.foo.save(j);
> db.foo.save(t);
> db.foo.find();
{ "_id" : ObjectId("4b8949d9cd50237b8573833b"), "name" : "mongo" }
{ "_id" : ObjectId("4b8949dbcd50237b8573833c"), "x" : 3 }
Você não precisa predefinir a coleção, que é criada automaticamente no salvamento da primeira estrutura. O campo
_id
é criado automaticamente e é a chave primária.Para apagar o objeto
j
:> j = db.foo.findOne({ name: 'mongo' });
> db.foo.remove(j);
Para apagar todos os objetos basta remover a coleção:
> db.foo.drop();
Vamos usar um pouco mais de lógica:
> for (var i=0; i<100; ++i) db.foo.save({ x: i, y: i*i });
Esse loop cria cem registros, com
x
variando de zero a noventa e nove e y
igual a seu quadrado:> db.foo.find();
{ "_id" : ObjectId("4b894c05cd50237b8573833e"), "x" : 0, "y" : 0 }
{ "_id" : ObjectId("4b894c05cd50237b8573833f"), "x" : 1, "y" : 1 }
{ "_id" : ObjectId("4b894c05cd50237b85738340"), "x" : 2, "y" : 4 }
{ "_id" : ObjectId("4b894c05cd50237b85738341"), "x" : 3, "y" : 9 }
{ "_id" : ObjectId("4b894c05cd50237b85738342"), "x" : 4, "y" : 16 }
{ "_id" : ObjectId("4b894c05cd50237b85738343"), "x" : 5, "y" : 25 }
{ "_id" : ObjectId("4b894c05cd50237b85738344"), "x" : 6, "y" : 36 }
{ "_id" : ObjectId("4b894c05cd50237b85738345"), "x" : 7, "y" : 49 }
{ "_id" : ObjectId("4b894c05cd50237b85738346"), "x" : 8, "y" : 64 }
{ "_id" : ObjectId("4b894c05cd50237b85738347"), "x" : 9, "y" : 81 }
{ "_id" : ObjectId("4b894c05cd50237b85738348"), "x" : 10, "y" : 100 }
{ "_id" : ObjectId("4b894c05cd50237b85738349"), "x" : 11, "y" : 121 }
{ "_id" : ObjectId("4b894c05cd50237b8573834a"), "x" : 12, "y" : 144 }
{ "_id" : ObjectId("4b894c05cd50237b8573834b"), "x" : 13, "y" : 169 }
{ "_id" : ObjectId("4b894c05cd50237b8573834c"), "x" : 14, "y" : 196 }
{ "_id" : ObjectId("4b894c05cd50237b8573834d"), "x" : 15, "y" : 225 }
{ "_id" : ObjectId("4b894c05cd50237b8573834e"), "x" : 16, "y" : 256 }
{ "_id" : ObjectId("4b894c05cd50237b8573834f"), "x" : 17, "y" : 289 }
{ "_id" : ObjectId("4b894c05cd50237b85738350"), "x" : 18, "y" : 324 }
{ "_id" : ObjectId("4b894c05cd50237b85738351"), "x" : 19, "y" : 361 }
has more
Consultas (queries)
É possível fazer consultas simples ou bem complexas assim como em modelos relacionais usando MongoDB.
Vamos obter uma contagem de objetos:
> db.foo.find().count();
100
Só os cinco primeiros objetos:
> db.foo.find().limit(5);
{ "_id" : ObjectId("4b894c05cd50237b8573833e"), "x" : 0, "y" : 0 }
{ "_id" : ObjectId("4b894c05cd50237b8573833f"), "x" : 1, "y" : 1 }
{ "_id" : ObjectId("4b894c05cd50237b85738340"), "x" : 2, "y" : 4 }
{ "_id" : ObjectId("4b894c05cd50237b85738341"), "x" : 3, "y" : 9 }
Agora os cinco seguintes:
> db.foo.find().skip(5).limit(5);
{ "_id" : ObjectId("4b894c05cd50237b85738343"), "x" : 5, "y" : 25 }
{ "_id" : ObjectId("4b894c05cd50237b85738344"), "x" : 6, "y" : 36 }
{ "_id" : ObjectId("4b894c05cd50237b85738345"), "x" : 7, "y" : 49 }
{ "_id" : ObjectId("4b894c05cd50237b85738346"), "x" : 8, "y" : 64 }
{ "_id" : ObjectId("4b894c05cd50237b85738347"), "x" : 9, "y" : 81 }
Para obter o elemento com valor de
x
vinte e quatro:> var e = db.foo.findOne({ x: 24 });
> print(e.y);
576
> print(tojson(e));
{ "_id" : ObjectId("4b894c05cd50237b85738356"), "x" : 24, "y" : 576 }
Consultas avançadas
Vamos complicar um pouco…
Para obter todos os registros com
x
maior que cinquenta:> db.foo.find('this.x > 50');
{ "_id" : ObjectId("4b894c05cd50237b85738371"), "x" : 51, "y" : 2601 }
{ "_id" : ObjectId("4b894c05cd50237b85738372"), "x" : 52, "y" : 2704 }
{ "_id" : ObjectId("4b894c05cd50237b85738373"), "x" : 53, "y" : 2809 }
{ "_id" : ObjectId("4b894c05cd50237b85738374"), "x" : 54, "y" : 2916 }
{ "_id" : ObjectId("4b894c05cd50237b85738375"), "x" : 55, "y" : 3025 }
{ "_id" : ObjectId("4b894c05cd50237b85738376"), "x" : 56, "y" : 3136 }
{ "_id" : ObjectId("4b894c05cd50237b85738377"), "x" : 57, "y" : 3249 }
{ "_id" : ObjectId("4b894c05cd50237b85738378"), "x" : 58, "y" : 3364 }
{ "_id" : ObjectId("4b894c05cd50237b85738379"), "x" : 59, "y" : 3481 }
{ "_id" : ObjectId("4b894c05cd50237b8573837a"), "x" : 60, "y" : 3600 }
{ "_id" : ObjectId("4b894c05cd50237b8573837b"), "x" : 61, "y" : 3721 }
{ "_id" : ObjectId("4b894c05cd50237b8573837c"), "x" : 62, "y" : 3844 }
{ "_id" : ObjectId("4b894c05cd50237b8573837d"), "x" : 63, "y" : 3969 }
{ "_id" : ObjectId("4b894c05cd50237b8573837e"), "x" : 64, "y" : 4096 }
{ "_id" : ObjectId("4b894c05cd50237b8573837f"), "x" : 65, "y" : 4225 }
{ "_id" : ObjectId("4b894c05cd50237b85738380"), "x" : 66, "y" : 4356 }
{ "_id" : ObjectId("4b894c05cd50237b85738381"), "x" : 67, "y" : 4489 }
{ "_id" : ObjectId("4b894c05cd50237b85738382"), "x" : 68, "y" : 4624 }
{ "_id" : ObjectId("4b894c05cd50237b85738383"), "x" : 69, "y" : 4761 }
{ "_id" : ObjectId("4b894c05cd50237b85738384"), "x" : 70, "y" : 4900 }
has more
Outra opção é usar o operador condicional
$gt
:> db.foo.find({ x: { $gt: 50 } });
Da mesma forma outros operadores. Por exemplo, todos os elementos com
x
entre vinte e três e vinte e seis, inclusive:> db.foo.find('23 <= this.x && this.x <= 26');
Ou:
> db.foo.find({ x: { $gte: 23, $lte: 26 } });
Os principais operadores são:
$lt
– menor que$gt
– maior que$lte
– menor ou igual a$gte
– maior ou igual a$ne
– diferente de$in
– está em (recebe uma lista)$nin
– não está em$mod
– resto igual a (recebe uma lista onde o primeiro valor é o divisor e o segundo o resto)$exists
– contém ou não o atributo$not
– negação de uma condição
Ordenação
A ordenação é feita usando o método
sort
. Por exemplo, para ordenar de modo descrescente pelo atributo y
:> db.foo.find().sort({ y: -1 });
Expressões regulares
Quando há campos com valor string, é possível usar expressões regulares:> db.foo.find({ name: /^mon.o$/i });
Índices
Quando você faz muitas consultas baseadas em um determinado atributo, é interessante criar um índice para ele. Por exemplo, se quisermos criar um índice para nosso atributox
:> db.foo.ensureIndex({ x: 1 });
Obs.¹: o atributo
_id
possui índice por padrão.Obs.²: é possível criar índices compostos.
Agregação
Não vou entrar nesse mérito, mas é possível criar agregações, como
GROUP_BY
de SQL. Para tanto veja a documentação oficial.Módulos de conexão com linguagens de programação
Há módulos para várias linguagens, que podem ser encontrados na lista de APIs.
O módulo que pude e me fascinou foi para Python. Sua instalação usando
easy_install
foi muito simples:bash$ sudo easy_install -U pymongo
E seu uso extremamente fácil devido à similiaridade entre dicionários de Python e JSON. A única reclamação que faço é o fato do método
db.auth()
do MongoDB ter sido traduzido como db.authenticate()
em Python, o que me fez perder alguns segundos tentando entender por que não funcionava.**
Espero que este artigo seja mais do que útil e incite o uso dessa intrigante ferramenta.
[]’s
Cacilhas, La Batalema