Atualizando e removendo objetos, operadores de array, operadores de buscas em arrays e operadores de negação.

Atualizando e Removendo dados

Agora o bicho vai pegar LOL.

UPDATE

No MongoDB não existe só uma forma de atualizar o documento, uma das formas já vimos neste post, que foi fazendo uma busca usando o findOne( ), e através do resultado modificamos e usamos a função save( ), porém esse caminho é grande, perceba que precisamos fazer a busca, salvar na variável, e modificar para depois salvar.

> var query = {name: 'Carterpie'}
> var p     = db.pokemons.findOne(query)
> p.name    = 'RatoCabeludo'
> db.pokemons.save(p)

Qual a melhor forma?

Ele possui uma função chamada update( ) que tem esse objetivo de fazer tudo de uma só vez. Contém 3 parâmetros que veremos com mais detalhe cada um.

> db.colecao.update(query, modificador, options);

Info 1 O parâmetro options não é obrigatório.

Vamos inserir um objeto para modificarmos

> var poke = {name: "Testemon", attack: 8000,
        defense: 8000, height: 2.1,
        description: "Pokemon de teste"}
> db.pokemons.save(poke);
> var query = {name: /testemon/i}
> db.pokemons.find(query);

Info 2 Na variável query passamos o name, porém usamos a barra entre o nome, isso é uma REGEX, o i informa que não importa se é maiúsculo ou minúsculo. Assim fazendo uma busca Case insensitive

Me retornou:

{
  "_id": ObjectId("5665171cd394bd50ba306acd"),
  "name": "Testemon",
  "attack": 8000,
  "defense": 8000,
  "height": 2.1,
  "description": "Pokemon de teste"
}

Vamos modificar o Testemon

> var query = {name: /testemon/i}
> var mod   = {description: "Mudei aqui"}
> db.pokemons.update(query, mod)

Agora agora faça uma busca

> db.pokemons.find(query);
{
  "_id": ObjectId("5665171cd394bd50ba306acd"),
  "description": "Mudei aqui"
}

Ué cadê meus outros campos ?

hahaha fiz de propósito, essa forma é incorreta, para isso precisamos saber alguns operadores de modificação. Concerte a merda Adicione os valores de volta para continuarmos.

Operadores de modificação

$set: modifica um valor caso já exista, caso não exista, o $set irá criar o campo com esse valor que está alterando.

> var mod = {$set:
         {
           name:'Testemon', attack: 8000,
           defense: 8000, height: 2.1,
           description: "Pokemon de teste"
         }
     }
> db.pokemons.update(query, mod)

$unset: remove campos.

> var mod = {$unset: {height: 1}}
> db.pokemons.update(query,mod)

Info 3 Informe 1 (true) nos campos desejável, assim removendo o campo.

$inc: para incrementar um valor e caso o campo não exista, ele irá criar o campo e setar o valor, e para decrementar, passe o valor negativo.

> var mod = {$inc:{attack:1}}
 //-1 para decrementar
> db.pokemons.update(query,mod)

Nos documentos também temos arrays, e se agora queremos também trabalhar com eles, precisamos saber os seus operadores.

Operadores de Array

$push: ele adiciona um valor ao campo do array caso ele já esteja no documento, e caso não exista esse array, ele irá criar esse campo do tipo array que está passando. Caso o campo não existe e não for um array, irá retornar um erro.

> var mod = {$push: {moves: 'choque de trovão'}}
> db.pokemons.update(query, mod)
> db.pokemons.find(query)
{
  "_id": ObjectId("5665171cd394bd50ba306acd"),
  "description": "Pokemon de teste",
  "name": "Testemon",
  "attack": 8001,
  "defense": 8000,
  "moves": [
    "choque de trovão"
  ]
}

$pushAll: se utiliza quando queremos passar mais de um valor para um array.

> var query = {name: /pokemon de teste/i}
> var attacks =[
                 'choque do trovão',
                 'ataque rapido',
                 'bola elétrica'
               ]
> var mod = {$pushAll: {moves: attacks}}
> db.pokemons.update(query, mod)
> db.pokemons.find(query)
{
  "_id": ObjectId("5665171cd394bd50ba306acd"),
  "description": "Pokemon de teste",
  "name": "Testemon",
  "attack": 8001,
  "defense": 8000,
  "moves": [
    "choque de trovão",
    "ataque rapido",
    "bola elétrica"
  ]
}

$pull: retira o valor do campo, caso o campo seja um array existente. Caso não exista ele não fará nada, e se o campo existir e não for array, ocorre em um erro.

> var mod = {$pull:{moves: 'bola elétrica'}}
> db.pokemons.update(query,mod)
> db.pokemons.find(query)
{
  "_id": ObjectId("5665171cd394bd50ba306acd"),
  "description": "Pokemon de teste",
  "name": "Testemon",
  "attack": 8001,
  "defense": 8000,
  "moves": [
    "choque do trovão",
    "ataque rapido"
  ]
}

$pullAll: inverso do $pushAll, retira todos os valores passado por um array.

> var attacks = [
               "choque do trovão",
               "ataque rapido"
                ]
> var mod = {$pullAll: {moves: attacks}}
> db.pokemons.update(query,mod)
> db.pokemons.find(query)
{
    "choque do trovão",
    "ataque rapido"
  "_id": ObjectId("5665171cd394bd50ba306acd"),
  "description": "Pokemon de teste",
  "name": "Testemon",
  "attack": 8001,
  "defense": 8000,
  "moves": [
    "choque de trovão"
  ]
}

Parâmetro OPTIONS do UPDATE

Lembra daquele último parâmetro que falei que não era obrigatório ?

> db.colecao.update(query, modificador, options);

OPTIONS

Para que ele serve ?

Simples, para configurar alguns valores diferentes do padrão em nosso update. Possui os seguintes parâmetros:

{
  upsert:       boolean
  multi:        boolean
  writeConcern: document
}

upsert

Lembra de quando fazemos a busca e colocamos no parâmetro de modificação o valor a ser modificado ? Caso a query não seja encontrada, ele NÃO fará nada, e retornará para você:

WriteResult({
  "nMatched": 0,
  "nUpserted": 0,
  "nModified": 0
})

Tem como modificar esse comportamento ? Sim, o upsert serve justamente para isso, por padrão o valor dele é false, com isso não fará nada, mas se modificar para true, ele insere o objeto que está sendo passado como modificação.
Vamos ao seguinte exemplo, modificando o valor do ‘upsert’:

> var query   = {name : 'esse campo nao existe'}
> var mod     = {$push: {moves: 'campo de fogo'}}
> var options = {upsert: true}
> db.pokemons.update(query, mod, options)
WriteResult({
  "nMatched": 0, //não encontrou
  "nUpserted": 1 //porém fez um upsert
  "nModified": 0,
  "_id": ObjectId("567df96b8c9d5a59c75d1501")
  //objeto que foi inserido
})
> db.pokemons.find(query)
{
  "_id": ObjectId("567df96b8c9d5a59c75d1501"),
  "name": "esse campo nao existe",
  "moves": [
    "choque de fogo"
  ]
}

Percebeu que ele criou um novo documento ? =)

$setOnInsert: serve para que podemos colocar um documento que seja inserido caso o upsert seja true e aconteça essa inserção.
Vamos fazer um exemplo que seta os valores comuns para nosso objeto caso ele não seja encontrado no nosso update.

> var query= {name : 'naoexiste'}
> var mod  = {$push:
                {moves: 'campo de água'},
                $setOnInsert:{
                 attack: null,
                 defense: null,
                 height: null,
                 description: "Sem informações"
                }
             }
> var options = {upsert: true}
> db.pokemons.update(query, mod, options)
WriteResult({
  "nMatched": 0,
  "nUpserted": 1,
  "nModified": 0,
  "_id": ObjectId("567dffac8c9d5a59c75d1502")
})
> db.pokemons.find(query)

Repare que agora ele fez uma inserção, pois não foi encontrada a query.

{
  "_id": ObjectId("567dffac8c9d5a59c75d1502"),
  "name": "naoexiste",
  "moves": [
    "campo de água"
  ],
  "attack": null,
  "defense": null,
  "height": null,
  "description": "Sem maiores informações"
}

MULTI

Lembra daqueles updates sem WHERE no banco relacional ? só faltava quebrar tudo pela frente:p lá precisamos usar o where para informar quais os objetos que você quer atualizar, caso contrário nem queira saber ☹ vai atualizar todos.
O MongoDB não deixa acontecer esse tipo de cagada situação. (✌╰_╯)☞
Por padrão ele só deixa alterar um de cada vez, a não ser que você passe por parâmetro desse multi como true.

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

Agora se você for verificar, vai ver que todos os documentos estão com uma active false. Só assim você consegue fazer um update em vários documentos, alterando seu campo multi.

WRITECONCERN

Ele descreve a garantia de que o MongoDB fornece ao relatar o sucesso de uma operação de escrita. Se você quer isso rápido, ele pode ter uma preocupação fraca, cajo queira uma preocupação forte, ele retorna mais demorado. Porém com a preocupação mais fraca, pode ocorrer de não persistir os dados, e não vai saber sobre aquele erro que pode ter acontecido após alguma coisa, agora com a preocupação mais demorada, ele espera o MongoDB confirmar a alteração de escrita pra você, então a garantia é maior. Mais sobre o assunto: Clique aqui

Buscas em arrays ?

Agora vamos aprimorar nossas buscas, aprendendo fazer buscas em arrays, mas para isso vamos inserir arrays em todos os nossos objetos. (Opa em todos ? Já sabemos fazer isso.)

> var query   = {}
> var mod     = {$set: {moves:['investida']}}
> var options = {multi: true}
> db.pokemons.update(query, mod, options)
WriteResult({
  "nMatched": 11,
  "nUpserted": 0,
  "nModified": 11
})

Vamos inserir mais dados nos arrays para depois fazermos buscas:

> var query = {name: /Arcanine/i}
> var mod   = {$push: {moves: 'veloz demais'}}
> db.pokemons.update(query, mod)

> var query = {name: /Psyduck/i}
> var mod   = {$push: {moves: 'lança chamas'}}
> db.pokemons.update(query, mod)

> var query = {name: /Metapod/i}
> var mod   = {$push: {moves: 'folha navalha'}}
> db.pokemons.update(query, mod)

Pronto! Agora já temos arrays em nossos objetos.

Operadores de buscas em arrays:

$in: ele retorna todos os documentos que tem no seu determinado array o valor passado por parâmetro, caso queira especificar mais valores do array, use apenas uma virgula para informar outro valor.

> var query = {moves: {$in: [/veloz demais/i]}}
> db.pokemons.find(query)
{
  "_id": ObjectId("564da193ab81d6513c255cac"),
  "name": "Arcanine",
  "description": "Arcanine is known for its high speed.",
  "type": "Fire",
  "attack": 60,
  "defence": 40,
  "height": 1.9,
  "moves": [
    "investida",
    "veloz demais"
  ]
}

$nin: É o inverso do $in, e retorna os objetos que não tiverem no valor passado no array.

> var query = {moves: {$nin: [/folha navalha"/i]}}
> db.pokemons.find(query)

Vai retornar todos os objetos que não tem no seu array moves o valor ‘folha navalha’.

$all: Ele é semelhante o $and, pois só vai retornar se todos os valores passado por parâmetro do array se forem encontrado no objeto.

> var query = {moves: {$all:
                            [
                            'folha navalha',
                            'investida'
                            ]
                       }
               }
> db.pokemons.find(query)

Operadores de Negação

$ne(not equal): ele nos ajuda a procurar todos os objetos que não tempo determinado valor.

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

E então vai retornar os diversos objetos que não tem o tipo grama. Bem simples. =)

Info 4 Cuidado ele não aceita REGEX. Você não pode passar uma regex usando esse operador, ocorrerá em um erro.

var query = {type: {$ne: /grama/i}} //<--JAMAIS FAÇA ISSO LOL

$not: retorna todos os objetos que não tenha determinada coisa atribuição.

> var query = {name: {$not:/Golbat/i}}
> db.pokemons.find(query)

REMOVE

É simples, para removermos um documento, utilizaremos a função remove( ) que é própria para isso, e de resto você já sabe, utilize os diversos modos de criar uma query para achar os documentos que queira excluir.

> var query = {name: /Golbat/i}
> db.pokemons.remove(query)

Info 5 Cuidado ele é multi true.

Se você der um remove sem nada na query, ele apagará tudo. =(
Cuidado para não fazer merda!!! ٩(-̮̮̃-̃)۶

Concluindo

E é isso, agora se divirta treinando modificando seus dados usando todos os operadores, tenta criar atualizações de vários dados simultâneos com javascript, abuse dos laços de repetições e condições, até a próxima, bye!