Be MEAN (MongoDB): Sobre upsert, multi, e operadores de query

Tempo de leitura de ~4 minutos

Olá de volta!

Acredita que no dia que peguei pra assistir essa aula e escrever esse resumo, eu demorei 1 hora para assistir 12 minutos?

Pois é, escrever esses resumos está tomando muito tempo! Por um lado é bom, porque quanto mais você se ocupa com um assunto melhor você aprende ele (vi um vídeo muito legal sobre isso ontem: https://youtu.be/PHnBUw1bUCU).

Porém infelizmente não acho que vou conseguir continuar fazendo isso até o final do curso. Parece que estou traduzindo a documentação do MongoDB. Aliás, escrever essa documentação deve dar um trabalho incrivelmente demorado, parabéns a quem faz isso!

Meu objetivo é pelo menos terminar de fazer os resumos do módulo de MongoDB, e aí arrumar outra estratégia para resumir, talvez com mapas mentais :)

Mas até lá, vou continuar escrevendo ;) Aliás, agora me sinto mais satisfeito, pois posso dizer que estou cumprindo mais uma meta para o blog em 2016 :D

Começando a aula

Relembrando a sintaxe do comando update(), temos:

db.collection.update(query, update, options)

E hoje veremos mais sobre o parâmetro options.

options

options é um objeto com a seguinte sintaxe:

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

{

upsert
Caso o objeto da sua query não seja encontrado para ser modificado, ele será criado automaticamente pelo update()
Valor padrão: false

Então se formos mudar um campo de um objeto e ele não encontrar esse objeto, o mongo irá criar um novo objeto com esse campo e valor, porém só com esse campo e valor que pedimos para modificar. Por exemplo, vamos buscar um pokemon com um nome inexistente e alterar o campo active:

var query = {name: /inexistente/i}
var mod = {$set:{active:true}}
var options = {upsert:true}
db.pokemons.update(query,mod,options)

O resultado será:

WriteResult({
  "nMatched": 0,
  "nUpserted": 1,
  "nModified": 0,
  "_id": ObjectId("5696d7c5d37af6f34881ad92")
})

Porém o objeto criado só contém:

{
  "_id": ObjectId("5696d7c5d37af6f34881ad92"),
  "active": true
}

Eu mesmo na primeira vez esperei que o mongo adicionasse o objeto com name: inexistente, mas ele só insere os campos do parâmetro mod.

Inserindo valores padrão para novos objetos ($setOnInsert)

Caso o upsert esteja ligado e o mongo não encontre o objeto a ser modificado, ele vai criar um novo com os campos e valores passados para modificação. Com o operador $setOnInsert, nós podemos setar valores padrão para o mongo usar nos novos objetos:

var query = {name: /NaoExisteMon/i}
var mod = {
  $set: {active: true},
  $setOnInsert: {
    name: "NaoExisteMon",
    attack: null,
    defense: null,
    height: null,
    description: "Sem maiores informações"}
}
var options = {upsert: true}
db.pokemons.update(query, mod, options)

O código acima vai alterar o campo active do objeto com name: NaoExisteMon, e caso o objeto não exista ele vai criar com os campos name, attack, defense, height, description e active, com seus respectivos valores.

Alterando múltiplos documentos

No MongoDB, caso você queira alterar mais de um documento, utilizando apenas uma query, é necessário mudar o multi para true. Como vimos mais acima, o multi faz parte das options.

Então caso queiramos inserir o campo active em todos os pokemons (e alterá-los para false caso já exista), fazemos:

var query = {}
var mod = {
  $set: {
    active: false
  }
}
var options = {
  multi: true
}
db.pokemons.update(query, mod, options)

Voltando ao find()

Operador $in

Nesse momento da aula foi apresentado o operador $in, do comando find(). Vamos direto ao exemplo:

var query = {moves:{$in: [/choque do trovão/i]}}
db.pokemons.find(query)

O operador $in vai retornar os documentos que possuírem os itens pedidos. No caso o campo moves é um array, e a busca vai retornar todos os documentos que tiverem o item choque do trovão no campo moves.

Operador $nin

E é claro que temos o operador $nin (not in), que faz justamente o inverso, retorna os documentos que não tiverem nenhum dos valores passados.

Operador $all

Se você conhece programação deve estar imaginando que também temos um operador tipo AND, e temos: $all.

Esse operador só retorna documentos que tenham todos os itens passados.

Operador $ne

Continuando a sequência de operadores, temos o $ne (not equal), que como se pode supor, retorna documentos cujo o valor do campo seja diferente do passado na query. Exemplo:

var query = {type: {$ne: 'grama'}}
db.pokemons.find(query)

Retorna todos os pokemons que não são do tipo grama.

Obs.: esse operador não aceita regex, caso tente usar algo como var query = {name: {$ne: /pikachu/i}}, vai dar o seguinte erro:

Error: error: {
  "$err": "Can't canonicalize query: BadValue Can't have regex as arg to $ne.",
  "code": 17287
}

Operador $not

Quase o mesmo que o operador anterior, porém inclui documentos que não contenham o campo especificado, e também permite regex.

Removendo documentos

remove()

O comando remove() remove todos os documentos encontrados na query, por exemplo:

var query = {name: \squirtle\i}
db.pokemons.remove(query)

drop()

O drop() serve para remover uma coleção inteira :)

Leia a documentação!

Lembre-se de que todos os tópicos aqui descritos estão melhor explicados na documentação oficial do MongoDB ;)

Novo Visual do Blog!

Que prazer em ver esse visual novo, limpo e bonito! Confesso que o tema não é meu, mas é tão bonito que decidi usar assim mesmo. O link d...… Continue reading

Ano novo, novas metas

Published on January 08, 2016