quarta-feira, 23 de dezembro de 2015

MongoDB - Sharding


Como forma de manter a alta performance na leitura e escrita de dados, deve ser adicionado mais máquinas para dividir os dados, isso é o que chamamos de Sharding. Isso proporciona um crescimento horizontal.

A diferença de crescimento horizontal e vertical é que no vertical ele irá exigir a máquinas cada vez mais potentes para poder atender a demanda, já a horizontal é vai utilizar várias maquinas para dividir o processamento. As maquinas utilizadas no crescimento horizontal não precisam ser de alta performance, ela possibilita o uso de máquinas de pequeno e médio porte.

O cluster no MongoDB, possui 3 serviços diferentes:
shards
config servers
router

Os shards que é onde ficam os dados, os config servers são os servidores de configuração do servidor e os routers que são os servidores que recebem as requisições e busca o shard correto para executar a ação. A aplicação sempre vai se conectar ao router, que usará os metadados que são só config servers para saber em qual shard ele deve se conectar.

Criando um cluster…

Primeiro (config server)
Precisamos criar uma pasta com o nome configdb, dentro de data que fica na pasta raiz. Essa pasta será usada para o nosso config server.
cd /
mkdir /data/configdb
mongod --configsvr --port 27010

O ideal é criamos mais de um config server, porque caso o nosso config caia o router ficar perdido. Então para evitarmos falhas, devemos criar outros config.

Segundo (router)
Agora iremos levantar o nosso router, passando a porta do nosso config server. Lembre-se de executar em uma nova aba/janela.
mongos --configdb localhost:27010 --port 27011

Terceiro (shards)
Criaremos pastas onde ficaram nossas shards, dentro também da pasta data.
cd /
mkdir /data/shard1 && mkdir /data/shard2 && mkdir /data/shard3

E iremos levantar cada shard no terminal. Cada shard precisa ser executado em aba/janela diferente.

cd/
mongod --port 27012 --dbpath /data/shard1

cd/
mongod --port 27013 --dbpath /data/shard2

cd/
mongod --port 27014 --dbpath /data/shard3

Agora precisamos registrar nossos Shards no nosso Router. Para isso devemos conectar ao Router:
mongo --port 27011 --host localhost

Depois registramos os shards, passando o ip e a porta:
sh.addShard(“localhost:27012”)
sh.addShard(“localhost:27013”)
sh.addShard(“localhost:27014”)

Feito isso, vamos especificar qual database iremos shardear com o comando
sh.enableSharding(“database”)

E agora iremos selecionar a collection, no primeiro parâmetro iremos passar o nome da database e da collection e como segundo parâmetro o campo que era irá quebrar para saber a faixa de dados que vai ficar em cada shard.
sh.shardCollection(“database.collection”, {_id: 1})
No exemplo assim, passamos a _id para ser dividido.

Agora quando formos fazer inserção de dados no nosso cluster, basta executar no nosso router.

Até a próxima ;)

MongoDB - Criando Replicas



Com a necessidade de criar um blog para um curso, tive a ideia de aproveitar o blog e junto com alguns amigos fazer postagens de assuntos relacionados a Computação, como: Teoria para grafos, Telecomunicações, Sistemas Operacionais, Desenvolvimento, entre outros.
As postagens servirão como estudo tanto para os autores dos post's, como para todos os leitores que tem interesse nos assuntos abordados e que desejam aprender cada vez mais. Essa é a nossa forma de poder ajudar amigos e colegas da área, compartilhando conhecimentos adquiridos de forma simples e didática para um fácil entendimento.

Nesse post irei explicar passo a passo como construir Replicas no MongoDB, onde construiremos localmente um conjunto de 3 Replicas.

Todos os comandos serão executados no terminal.

Primeiro
De inicio precisamos criar 3 pastas novas dentro de data (aquela mesma pasta que foi preciso criar na instalação do MongoDB), são nessas pastas que serão armazenados os dados das Replicas. Segue o comando para criar as pastas pelo termial:
cd /
mkdir /data/rs1
mkdir /data/rs2
mkdir /data/rs3

Segundo
Pare todos os processos do mongod caso esteja com algum rodando. E execute os seguintes comandos, cada um em uma aba/janela do terminal:

cd /
mongod --replSet replica_set --port 27017 --dbpath /data/rs1

cd /
mongod --replSet replica_set --port 27018 --dbpath /data/rs2

cd /
mongod --replSet replica_set --port 27019 --dbpath /data/rs3
Depois do parâmetro --replSet é colocado o nome do nosso conjunto de replicas, logo em seguida é passado o número da porta que será usado e o caminho da pasta que ficará as Replicas.

Terceiro
Agora vamos levantar o nosso client em uma nova aba/janela, passando a porta da nossa replica primária, que no caso é a primeira que criamos.
Mongo --port 27017

Quarto
No mongo client, criaremos uma variável que conterá as configurações para a criação da nossa ReplicaSet:
rsconf = {
   _id: "replica_set",
   members: [
    {
     _id: 0,
     host: "127.0.0.1:27017"
    }
  ]
}
Onde como você pode ver, no _id passamos o nome do nosso grupo de replicas e uma array de membros adicionando nossa primeira replica, a nossa replica primária.

Quinto
Agora iremos inicializar a nossa ReplicaSet ainda no mongo client, passando a variável que criamos no passo anterior:
rs.initiate(rsconfig)

Se após você receber a configuração da inicialização e você for na aba que está sendo executado o servidor mongo de endereço 127.0.0.1:27017, você verá algumas mensagem como a criação do oplog e o seu tamanho, a alocação dos arquivos, a inicialização a replicação e a transação do status, onde no final ficará como PRIMARY.

Sexto
Agora iremos adicionar as outras duas replicas, com o seguinte comando (ainda no mongo client):
rs.add(“127.0.0.1:27018”)
rs.add(“127.0.0.1:27019”)

Pronto! Replicas criadas.

Os comandos de escrita são feitos apenas na replica primária, se você tentar fazer uma alteração ou até mesmo uma seleção na replica secundaria, verá que o MongoDB não vai deixar. As modificações feitas na replica primaria serão automaticamente sincronizadas com as outras replicas.

Status
Você pode executar o comando
rs.status()
Para ver o status da replica, vendo o nome do grupo, os membros que fazem parte, o estado de cada membro (primário ou secundário). É muito interessante.

Também podemos ver o status do oplog, executando
rs.printReplicationInfo()
Onde mostra o tamanho do oplog e quando foram registrado as alterações.

No MongoDB temos um comando para rebaixar nossa replica primária, isso serve para você poder simular o que aconteceria se o servidor da nossa replica caísse. O comando é o seguinte:
rs.stepDown()

Quando a replica primaria cai. As outras replicas fazem uma votação entre elas para eleger qual será a replica principal, essa é a nossa garantia de que mesmo que nosso servidor principal caia, nossa base de dados continuara ativa, disponível.

Não perca nossos post's ;)

Aaaaah!

Caso você crie um número par de replicas é preciso criar um arbitro, pois se sua replica primaria cair, pode haver um empate na votação, precisando de um arbitro que terá o voto do desempate.

Para criarmos devemos criar outra pasta, dentro de data no diretório raiz.
cd /
mkdir /data/arb

Depois levante o mongod em uma outra aba/janela utilizando o comado:
mongod --port 30000 --dbpath /data/arb –replSet replica_set

Fazendo isso, vá no client da nossa replica primária e adicione o árbitro:
rs.addArb(“127.0.0.1:30000”)

terça-feira, 22 de dezembro de 2015

MongoDB - Extras

Nesse extra, iremos aprender as seguintes funções:

find().length()
count()
distinct()
limit().skip()

find(query).length() X count(query)
Essas duas funções fazem a mesma coisa, retornam a quantidade de documentos encontrado na busca. Mas como sempre a uma diferença, o count() é mais rápido que se usar o find().length(), já que esse último traz todos os documentos para a memorias e faz uma interação dos dados, fazendo uma contagem dos documentos, o que gasta mais tempo.
db.collection.find(query).length()
db.collection.count(query)

distinct('campo')
Essa função serve para retornar os valores distintos do campo. Por exemplo, usando a nossa database Pokedex, nossa collection possui vários pokémons de vários tipos (water, fire, electric, …), muitos desses tipos se repetem. Se utilizarmos o distinct nesse campo, ele irá retornar cada tipo de existente na nossa collection, sem repeti-los. Faça o teste.
db.pokemons.distinct('types')
Se quiser saber quantos tipos distintos existem, basta fazer…
db.pokemons.distinct('types').length
Também podemos ver os tipos de pokémons em ordem alfabética (A-Z)
db.pokemons.distinct('types').sort()
E se quiser na ordem inversa (Z-A)
db.pokemons.distinct('types').sort().reverse()

Fácil, extremamente fácil…

E agora as relações…

Relacionamento
O relacionamento no Mongo é diferente de bancos de dados relacionais. No Mongo não existe o JOIN usado para juntar duas tabelas que possuam alguns campos específicos iguais, que são usados em bancos relacionais.

No Mongo existem duas formas de fazer esse relacionamento, a forma Manual e a DBRef. A manual nada mais é, do que do que salvar o _id de uma coleção em outra coleção que estamos relacionando, a segunda forma, a DBRef nada mais é do que uma convenção para representar um documento relacional, isso inclue: $ref (nome da coleção a ser referenciada), $id (o ObjectId do documento referenciado) e $db (a database onde a coleção referenciada se encontra).

Explain
O explain mostra para a gente o que o banco está fazendo, mostrando como ele executa as query internamente. Todos os comando que fazemos são passados para o interpretador e convertido para uma forma que o Mongo entenda e possa executar. Crie uma query e execute o seguinte comando:
db.pokemons.find(query).explain()
Como resultado, você verá que ele retornar uma série de informações, como por exemplo, o namespace que contem o nome da database e da collection, o parsedQuery que mostra como a query foi interpretada pelo Mongo, o serverInfo que mostra informações do servidor como o nome do host, porta e versão do Mongo.
Você pode obter mais informações, se fizer da seguinte forma:
db.pokemons.find(query).explain(“executionStats”)
Isso trará informações extras, como a quantidade de arquivos retornados com o find executado, total de arquivos examinados, o tempo que levado para fazer a pesquisa, entre outras coisas.

Index
Índice é uma forma de deixar uma busca mais rápida. Ao criamos um index em uma collection, o Mongo irá tratar esse campo de forma diferente, fazendo pesquisas por esse campo de forma mais rápida. Você pode ver o index da sua collection com o seguinte comando:
db.collection.getIndexes()
E pode criar index, com esse outro:
db.collection.createIndex({campo: 1})
E se quiser remover algum index que você já criou:
db.collection.dropIndex({campo: 1})

GridFS
É um sistema de arquivos do MongoDB que permite armazenar arquivos binários (fotos, vídeos) diretamente no banco. Arquivos de documento do tipo BSON é de 16 Mb, para armazenarmos arquivos maiores utilizamos o GrindFS.
Por exemplo, se fossemos adicionar um video de formato mp4, no sistema GridFs, bastaria executar:
mongofiles -d nome_database -h ip_do_host put video.mp4
Para fazer isso localmente, podemos colocar como ip_do_host o ip local, 127.0.0.1. Lembrando que o nome_database é a database que será criada para armazenar os arquivos binários.

Lembrando que esse comando é um binário e não pode ser feito no terminal do Mongo. Deve ser feito no terminal normal.

Replica
A replica é o espelhamento dos dados de um servidor para outro. Um conjunto de replicas é chamado de ReplicaSet, onde cada ReplicaSet pode conter 50 replicas.
A replica funciona da seguinte forma: qualquer escrita feita na replica primaria, a primaria irá replicar para as secundarias. Isso ocorre em duas etapas: Initial Sync e a Replication.

Initial Sync
Esse é a primeira etapa na replicação. Onde ele consulta cada coleção em cada banco de dados de origem e insere todos os dados em suas próprias cópias dessa seleção, é dessa forma que é feita a clonagem dos bancos de dados. Esse processo de clonagem apenas copia os dados válidos, omitindo documentos inválidos.
Depois ele aplica as alterações para o conjunto de dados, para que depois possa ser feito a transação para o estado secundário.

Replication
Depois de já ter nossas replicas construídas, a Replication vai continuar replicando e sincronizando os dados. Ele sempre fica rodando para que cada alteração no primário seja replicado, mantendo os membros das Replicas (ReplicaSet), atualizados.

Oplog
É o log de operações, qualquer alteração feito na replica primária é colocada a ação no oplog que é uma capped collection (coleções de tamanho fixo) especial. O MongoDB aplica as alterações no primário e, em seguida, registra as operações no oplog do primário. Onde os membros secundários, copiam e aplicam essas operações do oplog em um processo assíncrono.

As replicas servem para garantir que tenhamos a nossa base de dados em outros servidores, para caso aconteça algum imprevisto no nosso servidor principal. Por isso sempre tenha uma replica como garantia, pois nenhum servidor é 100%.

Como fazer replicas?

Veja no nosso próximo post ;)

MongoDB - Update


Nesse post será abordado a atualização no banco de dados.

Se você leu o post sobre a inserção, viu que existe o save, que serve tanto para inserir documentos como para alterar. Para alterarmos o documento no save precisamos busca o documento, modificar e salvar, já no update você não tem todo esse trabalho, até porque ele permite que você altere mais de um documento de uma vez.

A função update recebe 3 parâmetros:
Query
Modificação
Options

E sua sintaxe é:
db.collection.update(query, mod, options)

No update o parâmetro options é opcional.

As buscas que fazemos é case-sensitive, para fazermos pesquisas case-insensitive é preciso usar RegExp (expressões regulares) do JavaScript. Assim:
/pikachu/i

Agora iremos fazer uma atualização no documento do Pikachu, adicionando o campo description ao documento…

Vamos lá…

Execute os seguintes comandos...

var query = {name: /pikachu/i}
query = db.pokemons.findOne(query, {_id: 1})
var poke = db.pokemons.findOne(query, {_id: 0})
var mod = {description: “O Pikachu é um dos pokémons mais famosos.”}
db.pokemons.update(query, mod)
db.pokemons.findOne(query)

Viu o que aconteceu? Perdemos os campos que tinhamos e ficou apenas o _id e a description. Por isso fiz aquela query receber o _id do documento, pois não teríamos mais como pesquisar pelo nome. Sabendo que perderia os dados também salvei eles na variável poke para que pudéssemos deixar como estava antes. Então faça...
db.pokemons.update(query, poke)

Para podermos atualizar corretamente os dados, precisamos usar operadores de modificação.

Operadores de modificação

O operador $set modifica um valor ou cria ele, caso não exista. Sua sintaxe é a seguinte:
{ $set: {campo: valor, campo: valor, …} }
Se queremos adicionar a description precisamos fazer o mod da seguinte forma:
var mod = {$set: {description: “O Pikachu é um dos pokémons mais famosos.”} }
db.pokemons.update(query, mod)

Se podemos criar e alterar campos, também podemos remove campos de nossos documentos, basta usar o $unset. Sua sintaxe:
{$unset: {description: 1}}
Para apagarmos a description que inserimos no documento, basta fazermos isso…
var mod = {$unset: {description: 1}}
db.pokemons.update(query, mod)

Para fazermos o incremento em campos numéricos, usamos o $inc onde passamos o campo e a quantidade que desejamos incrementar, caso passe um valor negativo será decrementado e caso o campo não exista, o campo será criado e setado com o valor que você passou.
{$inc: {campo: valor}}

Veja como é fácil incrementar. Iremos adicionar +1 no attack do Pikachu.
var mod = {$inc: {attack: 1}}
db.pokemons.update(query, mod)

Para podermos fazer modificações em campos que sejam array, precisamos dos Operadores de Array.

Para inserirmos elementos no campo que seja Array, usaremos o $push. Caso o campo que você vá inserir não seja uma Array, ele irá retornar um erro.
{$push: {campo: valor}}

Vamos adicionar moves ao Pikachu.
var mod = {$push: {moves: “Choque do trovão”}}
db.pokemons.update(query, mod)

O $push adiciona apenas um valor por vez ao campo. Para adicionarmos mais de um valor de uma única vez, devemos utilizar o $pushAll:
{$pushAll: {campo: [Array_de_valores]}}

Mais uma vez, se podemos adicionar valores em um capo do tipo array, também podemos remover valores desses campos. Basta utilizar o $pull:
{$pull: {campo: valor}}

O $pull remove apenas um valor por vez. Para removermos mais de um valor de uma única vez, usaremos o $pullAll
{$pullAll: {campo: [Array_de_valores]}}

Todos esses operadores de modificação de array, se usados em campos que não são array irá retornar um erro.

Options

Com o objeto options podemos configurar alguns valores diferentes do padrão. O options possui os seguintes parâmetros:

{
upsert: boolean,
multi: boolean,
writeConcern: document
}

Por padrão o upsert e o multi são falsos.

Upsert
Esse parâmetro serve para caso o documento que você pesquise não seja encontrado pela query, ele irá criar e inserir um novo documento contendo apenas os campos passados no mod.

$setOnInsert
Esse operador serve para você definir valores que serão adicionados quando ocorrer um upsert, afinal, você não vai querer que o upsert crie um documento com apenas um campo né!?

Como fazer isso?
Você passa esse operador no mod. Veja mais ou menos como ficaria:
var mod = { $set: {active: true}, $setOnInsert: {name: null, attack: null, defense: null, height: null, type: null} }
Então… Se você deixar o upsert setado como true e se ao fazer a busca no update e ele não encontrar o documento, ele automaticamente criara um documento contendo os campos do setOnInsert e com o campo set. Se ele encontrar o documento ele apenas faz o set.

Multi
Por padrão, o update permite que você modifique apenas um documento por vez, isso porque o multi vem setado como false, para evitar que você faça sem querer aquele famoso, update sem where. Para setar como true, basta:
var mod = {multi: true}

writeConcern
Esse operador descreve a garantia de que o MongoDB fornece ao relatar o sucesso de uma operação de escrita. Para saber mais, dê uma olhada na documentação do Mongo ;)

segunda-feira, 21 de dezembro de 2015

MongoDB - Find/FindOne


Nesse post será abordado a pesquisa no banco de dados.

Para brincarmos com as pesquisas seria bom que você tivesse um database com vários dados. Nesse post usaremos um banco com pokemons para as pesquisas.

Esse é o link da database. Copiei e salve em um arquivo com o nome pokemons.json e importe os dados.

Fiz minha importação
mongoimport --db pokedex --collection pokemons --drop --file pokemons.json

Vamos lá!

Nesse post iremos falar sobre o find e o findOne. Mas antes uma curiosidade sobre o _id (UUID – Universally Unique Identifier) esse atributo é automaticamente colocado em cada registro que você insere no seu banco. Eles é formado por:

4-bytes: valor que representa os segundo desde a época Unix;
3-bytes: identificador de máquina;
2-bytes: ID do processo;
3-bytes: contador, começando com um valor aleatório.

Voltando…

Primeiro o find. A sintaxe dele é a seguinte:
db.collection.find({clausulas}, {campos})
Onde as clausulas são as condições da pesquisa e os campos são os atributos que você quer que ele retorne na pesquisa. Clausulas e campos, são opcionais, se você não colocá-los a pesquisa irá retornar todos os dados da collection.

Vamos fazer uma consulta. Primeiramente iremos criar uma variável para colocar nossa query e em seguida executaremos a pesquisa. Na execução da pesquisa podemos guardar ou não o resultado, para guardar para usar uma variável recebendo a pesquisa, caso não queria guardar, basta apenas executar o find. Veja…

var query = {name = 'Pikachu'}
db.pokemons.find(query)
ou
var poke = db.pokemons.find(query)
poke

Execute e veja o que acontece.

Agora vamos adicionar os campos que queremos que a pesquisa retorne. Ao usarmos campos, iremos especificar o campo com 1 (TRUE) caso queira que ele retorne ou 0 (FALSE) caso não queira o campo. Veja a prática…
var fields = {name: 1, types: 1}

Ou seja, queremos que retorne apenas o nome e o tipo do pokemon, os outros atributos não serão retornados. Mas se não quisermos que ele retorne por exemplo o atributo created, variamos…
var fields2 = {created: 0}
Agora execute dois find, pois temos duas fields. E use nossa query criada no inicio e veja a diferença…

db.pokemons.find(query, fields)
db.pokemons.find(query, fields2)

Você pode ter percebido que nos dois casos o _id sempre apareceu. Por padrão ele sempre irá aparecer, se por algum motivo você não deseja receber, basta negar nos campos.

findOne
Bom… O findOne basicamente faz o mesmo que o find, ele pesquisa. A diferença é que ele retorna apenas um elemento, o primeiro elemento que ele encontra. Sua sintaxe é a praticamente a mesma do find, a diferença é que é acrescentado o One.

Então, todos os comandos feitos anteriormente podem ser feito com o findOne, basta substituir find por findOne.

Operadores Aritméticos
É comum usarmos operadores aritméticos em atributos que sejam do tipo numérico, mas no Mongo esses operadores são um pouco diferente. Veja como é no Mongo:

< é $lt (less than)
<= é $lte (less than or equal)
> é $gt (greater than)
>= é $gte (greater than or equal)

Veja na prática. Vamos ver quais pokemons tem um attack maior ou igual ao Pikachu
var query = {attack: {$gte: 55}}
db.pokemons.find(query)

Como você pode ver… o Pikachu não é o mais forte :O

Operadores Lógicos
Os operadores lógicos no Mongo também são um pouco diferentes, mas é fácil, veja…

OR é $or
Not OR é $nor
AND é $and

A sintaxe é a seguinte:
$or: [{cláusula}, {cláusula}]
$nor: [{cláusula}, {cláusula}]
$and: [{cláusula}, {cláusula}]

Para usarmos os operadores lógicos, precisaremos de no mínimo duas cláusulas que passaremos como objetos ({}).

Na prática…
var query = {$or: [{name: 'Pikachu'}, {name: 'Charmander'}]}
db.pokemons.find(query)


Operador Existencial
Você nunca tinha ouvido falar nisso né!? Psé… Como você já deve saber o Mongo é Schemaless, você não tem uma estrutura pré definida, o que permite que você insira dados com campos que outros objetos não tem. É ainda que entra o operador existencial, você usa ele na busca para retornar apenas os objetos que possuam aquele campo.

A sintaxe é simples:
db.collection.find({ nome_do_campo: {$exists: true} })


Para fazermos buscas em array precisamos usar outros operadores. Mas não se preocupe, é fácil.

Veja!

Caso deseja fazer uma busca em algum campo do tipo array e quer que retorne os documentos que possuam algum dos valores que você passou, basta usar o $in.
var query = {campo: {$in: [array_de_valores]}}
db.pokemons.find(query)

O $in é o OU na nossa busca em array.

No Mongo também temos o $nin, que retorna os documentos que não possuem os valores que você passou na pesquisa.
{campo: {$nin: [array_de_valores]}}
db.pokemons.find(query)

E se temos um “OU” também temos um “AND”, que é o $all. Ele apenas retorna os documentos que possuem todos os valores que você passar.
{campo: {$all: [array_de_valores]}}
db.pokemons.find(query)

Agora, por fim, um operador de negação, que no caso seria o diferente, o $not.
var query = {name: {$not: /pikachu/i}}
db.pokemons.find(query)
Nessa busca que fizemos, será retornado todos os pokemons que não possuam o nome Pikachu.

Por hoje, é isso. Até o próximo post!

sexta-feira, 18 de dezembro de 2015

MongoDB – Importação/Exportação e Insert/Save




Antes de aprendermos a fazer pesquisas no MongoDB, primeiramente iremos aprender os comando de exportação e importação para que você já possa importar alguns dados e comece a brincar com eles durante as consultas.

Exportação
Na exportação os dados da collection são salvos em um arquivo JSON.
mongoexport --db nome_do_database --collection nome_da_collection --out arquivo.json

Importação
Os dados salvos em um JSON são importados para uma collection do Mongo.
mongoimport --db nome_do_database --collection nome_da_collection --drop --file arquivo.json
Nesse comando o --drop apaga a collection do database que você selecionou caso ela exista, para que possa começar do zero.

Observação: Os comandos de importação e exportação devem ser feitos no terminal normalmente e com o servidor mongo ligado. A importação e exportação não é feita no cliente mongo como você pode estar pensando...

No GitHub tem alguns JSON que você importar e usa para testar os comandos.

Nesse post iremos aprender sobre as formas de inserirmos dados no Mongo.

Vamos lá!

No Mongo existem duas formas de inserirmos os dados, são elas
db.collection.insert(documento)
ou
db.collection.save(documento)

Primeiro iremos criar em uma variável com os dados da pessoa que iremos inserir na collection pessoa da database agenda que foi mostrado no post anterior. Para criarmos essa variável e inserir os dados nela, podemos usar comandos JavaScript já que o Mongo aceita isso, um exemplo é que se você fizer 2 + 2 no terminal do Mongo, ele executa e te da o resultado. Veja como é simples criar uma variável para inserirmos no na nossa collection:

var pessoa = {
... 'name': 'Barry Allen',
... 'phones': [{'carrier': 'Claro', 'number': 912345678}]
... }

Phones será uma array onde poderemos colocar mais de um número, caso a pessoa possua, por isso os [ ] (colchetes). E dentro desses colchetes podemos colocar vários objetos, cada objeto dentro de { } (chaves), lembrando que um objeto pode possui vários atributos. Como no exemplo mostrado os nosso objeto possui os atributos carrier e number. Agora outro exemplo onde phones possui dos objetos:

var people = {
    "name": "Hal Jordan",
    "phones": [
        {
            "carrier": "Claro",
            "number": 987654321
        },
        {
            "carrier": "Tim",
            "number": 956781234
        }
    ]
}

Fácil, né!?

Temos dois contatos como exemplo. Vamos inserir usando o insert.
Primeiro:
db.pessoa.insert(pessoa)
depois:
db.pessoa.insert(people)

Para cada inserção deverá aparecer algo semelhante a isso (estou usando o MongoHack)...

Inserted 1 record(s) in 3ms
WriteResult({
"nInserted": 1
})

Essa mensagem mostra o tempo levado para fazer a inserção e diz quantos documentos foram inseridos.

Agora o save. Pode ser estranho ter dois comandos para inserir objetos no nosso banco, mas existe uma diferença entre eles, para poderemos ver essa diferença precisaremos usar o comando findOne(). Os comando de pesquisa explicarei mais a fundo no próximo post e a diferença do save você verá na prática.

Continuando…

Vamos criar uma variável que será nossa query, essa variável irá conter o que queremos pesquisar no banco de dados. Iremos pesquisar o nome 'Barry Allen', para isso nossa variável precisara ter o atributo que irá verificar (no caso o name) e o nome. Vejá como fica…

var query = {'name': 'Barry Allen'}

Agora iremos usar uma outra variável para receber o valor da pesquisa para a nossa query…

var auxiliar = db.pessoa.findOne(query)

Um spoiler do próximo post: db.collection.find() ou db.collection.find({}) exibi todos os dados da collection, lembre se que no nosso caso a nossa coleção é pessoa.

A variável auxiliar irá receber de findOne() o resultado da busca para o nome Barry Allen… Se depois desse comando, você digitar auxiliar e der ENTER, você verá isso…

{
    "_id": ObjectId("567479879a3b551315ed44c8"),
    "name": "Barry Allen",
    "phones": [
        {
            "carrier": "Claro",
            "number": 912345678
        }
    ]
}

Fácil, fácil. Reparou no atributo “_id”? Ao inserirmos um objeto no banco, automaticamente é criado um identificador desse objeto, é a forma de diferenciarmos cada objeto. Podemos até ter dois objetos com os mesmo dados, mas ele serão diferentes, pois possuirão id's diferentes.

Agora iremos alternar nossa variável auxiliar, adicionando um atributo, o nickname (apelido) que receberá The Flash.

auxiliar.nickname = 'The Flash'

Você pode executar auxiliar, para ver como ficou com a modificação. Veja que essa modificação foi feita apenas na variável, para que seja inserida no banco de dados e atualizar o contato que tem o nome do Barry Allen, usaremos o save…

db.pessoa.save(auxiliar)

Você pode utilizar o comando…

db.pessoa.find()

Para ver todas as pessoas que inserimos, no caso, você poderá ver que o objeto com nome de Barry Allen possui um atributo a mais. Isso graças ao nosso save. Ai já deu para perceber a diferença né!?

E se fizesse isso com o insert? Iria da erro. Pois o save verifica se existe algum objeto com o mesmo id, caso tenha ele apenas altera, caso não tenha ela insere. Já o insert se você tentar fazer o mesmo processo trocando o save pelo insert, irá da erro, o Mongo vai dizer que já existe um objeto com o mesmo _id.

E é isso.

Agora você já sabe inserir e ver os dados. Até o próximo post ;)