sábado, 19 de janeiro de 2013

The Little MongoDB Book - Capítulo 1 - O Básico



Iniciaremos nossa jornada através dos mecanismos básicos do MongoDB. Obviamente, isso é fundamental para a compreensão do MongoDB, mas também vai nos ajudar a responder questões sobre onde ele se encaixa.
Existem seis conceitos simples que devemos entender:
  1. MongoDB tem o mesmo conceito de um banco de dados  que, provavelmente, você já conhece. Em uma instância do MongoDB você pode ter zero ou mais banco de dados, cada um sendo um recipiente de alto nível para qualquer dado.
  2. Um banco de dados pode ter zero ou mais coleções. Uma coleção pode ser comparada a uma tradicional tabela onde são armazenados os dados.
  3. Coleções são compostas por zero ou mais documentos. Mais uma vez, um documento pode ser comparado com uma linha de uma tabela.
  4. Um documento pode ser composto por um ou mais campos, semelhante a colunas de uma tabela.
  5. Os Índices no MongoDB funcionam como os seus homólogos de RDBMS.
  6. Cursores são diferentes dos outros cinco conceitos anteriores, mas são de grande importância também. Muitas vezes são esquecidos e merecem ter sua própria discussão. O importante a saber sobre os cursores é que quando um dado é solicitado ao MongoDB, um cursor é retornado. Neste cursor podemos executar operações como contagem ou navegação.
Recapitulando, MongoDB é composto por banco de dados que possuem coleções. Uma coleção é composta por documentos. Cada documento é constituído por campos. As coleções podem ser indexadas, o que melhora o desempenho de pesquisa e classificação. Finalmente, quando obtemos dados do MongoDB, fazemos isso através de cursores.

Por que usar uma nova terminologia (coleção vs. tabela, documento vs. linha e campo vs. coluna)? Só pra tornar as coisas mais complicadas? A verdade é que, apesar destes conceitos serem semelhantes aos seus homólogos de banco de dados relacionais, eles não são idênticos. A principal diferença vem do fato de que banco de dados relacionais define colunas a um nível de tabela, enquanto que um banco de dados orientado a documentos define campos a um nível de documento. Isso quer dizer que cada documento dentro de uma coleção pode ter seu próprio conjunto de campos. Portanto, podemos dizer que uma coleção é um recipiente.

Embora o entendimento disso seja importante, não se preocupe se as coisas ainda não estão claras. Não vai levar mais que algumas inclusões para ver o que isso realmente significa. Em última análise, o ponto é que uma coleção não é rigorosa sobre o que se passa nela, ela é sem esquema (schema-less) Cada documento controla seus respectivos campos. As vantagens e desvantagens disto será explorada em um capítulo mais adiante.

Vamos por a mão na massa. Se seu servidor ainda não está funcionando, inicie o mongod assim como o console do mongo. O console roda JavaScript. Existem alguns comandos globais que você pode executar, como help ou exit. Os comandos executado no banco de dados atual são executados através do objeto db, tais como db.help() ou db.stats(). Comandos que são executados em uma coleção específica são executados através do objeto db.COLLECTION_NAME, como db.customers.help() ou db.customers.count().




Servidor Mongo (mondod.exe)




Console Mongo (mongo.exe)
Siga em frente e digite db.help() no console e você terá uma lista de comandos que você pode executar através do objeto db.



Um pequena nota: Por ser um console JavaScript, se você executar um método e omitir os parênteses “()”, vai ver o corpo do método, ao invés de executá-lo. Eu só mencionei isso porque, a primeira vez que o fizer e obter uma resposta que começa com function (...){ você não será surpreendido. Por exemplo, se você digitar db.help (sem os parênteses), verificará a implementação interna do método ajuda.

Primeiro vamos usar o método use para trocar de base de dados. Vá em frente e digite use learn. Não importa que o banco ainda não exista. Quando criarmos a primeira coleção, o banco de dados learn será criado também. Agora que você está dentro de um banco de dados, pode começar a digitar comandos como db.GetCollectionNames(). Fazendo isso, você obterá uma matriz vazia ([]). Como as coleções são sem esquema, não é necessário criá-las explicitamente. Podemos simplesmente inserir um documento em uma nova coleção para ela ser criada. Para fazer isso, use o comando insert, fornecendo o documento que será incluído:

db.unicorns.insert({name: 'Aurora', gender: 'f', weight: 450})

A linha acima está executando insert na coleção unicorns, passando um único argumento. Internamente o MongoDB usa um formato JSON binário. Isso significa que, externamente, usamos muito JSON, como no caso acima. Se executarmos db.getCollectionNames() agora, vamos ver duas coleções: unicorns e system.indexes. A coleção system.indexes é criada automaticamente e contém informações sobre os índices de nosso banco de dados.

Agora você pode usar o comando find em unicorns para obter a lista de documentos:

db.unicorns.find()

Nota-se que, junto com os dados incluídos, surgirá o campo _id. Cada documento deve ter um campo _id único. Você pode gerar um ou deixar que o MongoDB gere um ObjectId para você. Na maioria das vezes, você provavelmente vai querer deixar que o MongoDB faça isso por você. Por padrão, o campo _id é indexado - o que explica o motivo pelo qual a coleção system.indexes foi criada. Você pode conferir o conteúdo de system.indexes através do comando:

db.system.indexes.find()

O que você está vendo é o nome do índice, o banco de dados e a coleção que foi criada e os campos incluídos no índice.

Agora, de volta a nossa discussão sobre coleções sem esquema. Insira um documento totalmente diferente em unicorns, tal como:

db.unicorns.insert({nome: 'Leto', gender: 'm', home: 'Arrakeen', worm: false})

E, mais uma vez use find para listar os documentos. Uma vez que sabemos um pouco mais, vamos discutir este comportamento interessante do MongoDB. No entanto, espero que você esteja começando a entender por que, não foi uma boa ideia o uso da terminologia tradicional de banco de dados.

Dominando os Seletores

Além dos seis conceitos que exploramos, há um aspecto prático do MongoDB que você precisa saber antes de passar para os tópicos mais avançados: seletores de consulta. Um seletor de consulta no MongoDB é como uma cláusula de uma instrução SQL. Como tal, você usá-o para encontrar, contar, atualizar e remover documentos de coleções. Um seletor é um objeto JSON, onde o mais simples seletor é {}, que corresponde à todos os documentos (null também funciona). Se quiséssemos encontrar todos os unicórnios do sexo feminino, poderíamos usar {gender: ‘f’}.

Antes de se aprofundar ainda mais nos seletores, vamos incluir mais dados em unicorns. Primeiro, remova os dados que colocamos até agora: db.unicorns.remove() (uma vez que não estamos fornecendo um seletor, todos os documentos serão removidos). Agora, digite as inclusões abaixo para “brincarmos” (sugiro que copie e cole):

db.unicorns.insert({name: 'Horny', dob: new Date(1992,2,13,7,47), loves: ['carrot','papaya'], weight: 600, gender: 'm', vampires: 63});
db.unicorns.insert({name: 'Aurora', dob: new Date(1991, 0, 24, 13, 0), loves: ['carrot', 'grape'], weight: 450, gender: 'f', vampires: 43});
db.unicorns.insert({name: 'Unicrom', dob: new Date(1973, 1, 9, 22, 10), loves: ['energon', 'redbull'], weight: 984, gender: 'm', vampires: 182});
db.unicorns.insert({name: 'Roooooodles', dob: new Date(1979, 7, 18, 18, 44), loves: ['apple'], weight: 575, gender: 'm', vampires: 99});
db.unicorns.insert({name: 'Solnara', dob: new Date(1985, 6, 4, 2, 1), loves:['apple', 'carrot', 'chocolate'], weight:550, gender:'f', vampires:80});
db.unicorns.insert({name:'Ayna', dob: new Date(1998, 2, 7, 8, 30), loves: ['strawberry', 'lemon'], weight: 733, gender: 'f', vampires: 40});
db.unicorns.insert({name:'Kenny', dob: new Date(1997, 6, 1, 10, 42), loves: ['grape', 'lemon'], weight: 690, gender: 'm', vampires: 39});
db.unicorns.insert({name: 'Raleigh', dob: new Date(2005, 4, 3, 0, 57), loves: ['apple', 'sugar'], weight: 421, gender: 'm', vampires: 2});
db.unicorns.insert({name: 'Leia', dob: new Date(2001, 9, 8, 14, 53), loves: ['apple', 'watermelon'], weight: 601, gender: 'f', vampires: 33});
db.unicorns.insert({name: 'Pilot', dob: new Date(1997, 2, 1, 5, 3), loves: ['apple', 'watermelon'], weight: 650, gender: 'm', vampires: 54});
db.unicorns.insert({name: 'Nimue', dob: new Date(1999, 11, 20, 16, 15), loves: ['grape', 'carrot'], weight: 540, gender: 'f'});
db.unicorns.insert({name: 'Dunx', dob: new Date(1976, 6, 18, 18, 18), loves: ['grape', 'watermelon'], weight: 704, gender: 'm', vampires: 165});

Agora que temos mais dados, podemos dominar os seletores. {field: value} é usado para encontrar os documentos onde field é igual a value. {field1: value1, field2: value2} é como fazer uma declaração and. Temos ainda os seletores especiais $lt, $lte, $gt, $gte e $ne que são usados para operações: menor que, menor ou igual que, maior que, maior ou igual que e não igual. Por exemplo, para obter todos os unicórnios do sexo masculino que pesam mais de 700 quilos, podemos fazer:

db.unicorns.find({gender: 'm', weight: {$gt: 700}}) or
db.unicorns.find({gender: {$ne: 'f'}, weight: {$gte: 701}})

O operador $exists é usado para verificar a presença ou ausência de um campo, por exemplo:

db.unicorns.find({vampires: {$exists: false}})

O resultado do comando acima deve ser um documento, o qual não possui o campo vampires.
O operador $or deve receber um conjunto de valores referentes aos dados que queremos:

db.unicorns.find({gender: 'f', $or: [{loves: 'apple'}, {loves: 'orange'}, {weight: {$lt: 500}}]})

O comando acima retornará todos os unicórnios femininos que gostam de maças ou de laranjas ou pesam menos que 500 quilos.

Há algo bem interessante acontecendo neste último exemplo. Note que o campo loves é uma matriz. O MongoDB suporta matrizes como se fossem objetos. Trata-se de um recurso incrivelmente útil. Uma vez que você começa a usá-lo, vai querer saber como sobreviveu até hoje sem ele. O mais interessante é a facilidade de selecionar um documento com valor numa matriz. Exemplo: {loves: ‘watermelon’} retornará qualquer documento onde watermelon é um valor da matriz loves.

Existem ainda mais operadores dos que foram vistos até agora. Um dos mais flexíveis é o $where.

Estão todos descritos na seção de consultas avançadas do site MongoDB. Falamos até agora apenas do básico que você precisa para iniciar, e, também, dos que você vai acabar usando na maior parte do tempo.

Até agora vimos como os seletores podem ser usados com o comando find. Eles também podem ser usados com o comando remove que vimos brevemente, com o comando count, o qual ainda não vimos, mas provavelmente você vai aprender sobre ele, e ainda, com o comando update o qual gastaremos maior tempo de aprendizado.

ObjectId gerado pelo MongoDB para o campo _id pode ser selecionado a seguinte maneira:

db.unicorns.find({_id: ObjectId("TheObjectId")})

Neste Capítulo

Não vimos ainda o comando update e também não apreciamos muitas coisas que podemos fazer com o find. No entanto, conseguimos deixar o MongoDB instalado e funcionando, vimos rapidamente os comandos insert e remove (não há muita para se ver neles do que vimos até agora). Introduzimos também o find e vimos tudo sobre seletores. Tivemos um bom começo e estabelecemos uma base sólida para os próximos capítulos. Acredite ou não, você sabe mais do que há pra saber sobre MongoDB - ele realmente é para ser rápido e fácil de aprender e ainda mais fácil de usar. Eu recomendo que você “brinque” com sua cópia local antes de prosseguir. Inclua documentos diferentes. se possível em novas coleções, e se familiarize com os diferentes seletores. Use o findcount e remove.