domingo, 21 de abril de 2013

The Little MongoDB Book - Capítulo 2 – Atualizado Documentos


No capítulo 1, apresentamos três das quatro operações CRUD (create, read, update, e delete). Este capítulo é dedicado a operação: update. A operação update tem alguns comportamentos surpreendentes, motivo pelo qual dedicamos um capítulo inteiro a ela.



Atualização: Substituição Versus $set

A maneira mais simples de executar o update é através de dois argumentos: o seletor (where) e o campo que será atualizado.  Por exemplo: Se Roooooodles ganhou um pouco de peso, podemos executar:

db.unicorns.update ({nome: 'Roooooodles'}, {peso: 590})

(Se você já “brincou” com sua coleção unicorns e a mesma não tem mais os dados originais, remova todos os documentos e inclua novamente como no capítulo 1).

Se o código acima fosse em um sistema em produção, provavelmente a atualização ocorreria através do _id do documento, mas como não conhecemos o _id gerado pelo MongoDB, vamos usar o campo name.  Visualize agora o documento atualizado:

db.unicorns.find ({nome: 'Roooooodles'})

Você já deve ter percebido a primeira surpresa do comando update.  Nenhum documento foi encontrado pelo find acima.  Isso porque, o segundo parâmetro de update é usado como replace do documento original.  Em outras palavras, o update localiza o documento pelo name e substitui todo esse documento encontrado por um novo documento (o segundo parâmetro).  Tal procedimento é diferente de como o comando update do SQL funciona.  Em alguns casos, tal procedimento é o ideal e pode ser aproveitado para atualizações dinâmicas.  No entanto, quando tudo o que se quer fazer é alterar o valor de um ou de alguns campos, o melhor a fazer é usar o modificador $set:

db.unicorns.update ({peso: 590}, {$ set: {nome: 'Roooooodles ", dn: new Date (1979, 7, 18, 18, 44), ama: [' maçã '] sexo:' , M 'vampiros: 99}})

O código acima irá repor o documento perdido anteriormente. Observe que o valor de weight não será substituído, uma vez que ele não foi especificado.  Agora se executar:

db.unicorns.find ({nome: 'Roooooodles'})

Conseguimos o resultado esperado.  Portanto, a forma correta de atualizar o peso é:

db.unicorns.update ({nome: 'Roooooodles'}, {$ set: {peso: 590}})

Modificadores da Atualização

Além de $set, podemos citar outros modificadores que fazem coisas interessantes.  Todos esses modificadores de atualização trabalham sobre os campos.  Por exemplo, $inc é usado para incrementar uma determinada quantidade positiva ou negativa.  Por exempo, se Pilot está com valor errado no campo vampires, podemos corrigir executando:

db.unicorns.update({name: 'Pilot'}, {$inc: {vampires: -2}})

Se de repente Aurora começou a gostar de açúcar, poderíamos acrescentar um valor ao campo loves, através do modificador $push. Lembre-se que loves é um campo array.

db.unicorns.update({name: 'Aurora'}, {$push: {loves: 'sugar'}})

Você vai encontrar mais informações sobre outros modificadores de atualização no site do MongoDB.

Upserts

Um das surpresas mais agradáveis de usar update é sua total compatibilidade com upserts.  Um upsert atualiza o documento quando encontrado, caso contrário faz a inclusão do mesmo.  Upserts são úteis em determinadas situações.  Para habilitar o upserting usamos true como terceiro parâmetro no comando update.
Um exemplo simples é o contador de visitas de um site.  Se quisermos uma contagem em tempo real, teríamos que verificar se o registro já existe para a página, e, com base nisso, decidir executar uma atualização ou inclusão.  Com o terceiro parâmetro omitido (false), nada acontece:

db.hits.update({page: 'unicorns'}, {$inc: {hits: 1}});
db.hits.find();
No entanto, se habilitarmos o upserts, o resultado é bem diferente:

db.hits.update({page: 'unicorns'}, {$inc: {hits: 1}}, true);
db.hits.find();
Uma vez que não existem documentos com o campo page igual a unicorns, um novo documento é incluído.  Se você executar novamente, o documento existente será atualizado e o campo hits será incrementado para 2.

db.hits.update({page: 'unicorns'}, {$inc: {hits: 1}}, true);
db.hits.find();

Múltiplas Atualizações

Uma última surpresa que update tem a oferecer é que, por padrão, ele atualiza um único documento.  Até agora, para os exemplos que vimos, isso pode parecer lógico.  No entanto, se você executou algo como:

db.unicorns.update({}, {$set: {vaccinated: true }});
db.unicorns.find({vaccinated: true});

o resultado esperado para o código acima seria que todos os unicórnios estivessem com valor true para o campo vaccinated, mas não foi o que ocorreu.  Para obter esse comportamento, um quarto parâmetro deve ser definido como true.

db.unicorns.update({}, {$set: {vaccinated: true }}, false, true);
db.unicorns.find({vaccinated: true});

Neste Capítulo

Este capítulo conclui nossa introdução às operações básicas de CRUD disponíveis para uma coleção.  Vimos os três comportamentos interessantes do update.  Primeiro, ao contrário de uma atualização SQL, o update do MongoDB substitui inteiramente o documento.  Devido a isso, o modificador $set torna-se muito útil.  Em segundo lugar, o update suporta upsert, particularmente útil quando combinado com o modificador $inc.  Finalmente, por padrão, update atualiza apenas o primeiro documento encontrado.

Lembre-se que estamos conhecendo o MongoDB a partir do ponto de vista de seu console.  O drive ou biblioteca que você usar poderá alterar esses comportamentos ou expor uma API diferente.  Por exemplo, o driver do Ruby, junta os dois últimos parâmetros em um único
hash: {:upsert => false, :multi => false}.Da mesma forma, o driver do PHP, junta os dois últimos parâmetros em uma matriz.