find

Lembrando da aula anterior quando falei que a busca com find retorna um cursor onde você deve iterar nele para buscar seus dados, hoje veremos a diferença dele para o findOne.

Como havia dito, o Mongoose irá converter esse cursor para Array então sempre quando quisermos LISTAR algo iremos utilizar o find.

CUIDADO

Mesmo você buscando diretamente com o _id

_id

Esse _id que vocês devem ter visto nos registros inseridos nada mais é que um UUID.

Ele também é conhecido como ObjectId e ele é um tipo do BSON de 12-bytes, cconstruído usando:

4-bytes: valor que representa os segundos 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. Sim essa porra é "universalmente única"!

O _id é nossa chave primária, olha aí relational-guys, é com ele que fazemos consultas específicas, por favor não esqueça disso!!!

query

Para facilitar nossa vida iremos criar um JSON para nossa query, para isso iremos criar um JSON da seguinte forma:

var query = {name: 'Pikachu'}

Isso significa que iremos pesquisar apenas os Pokemons com o name igual a Pikachu.

Esse nosso objeto de query tem a mesma funcionalidade do tão conhecido SELECT dos bancos relacionais.

Eu já escrevi sobre isso em 2010 no iMasters - Como utilizar selects com MongoDB

Claro que é bem defasado e escrito ainda com PHP ehhehehhehhe.

fields

Se o nosso JSON de query é o WHERE do relacional, logo o JSON fields será o nosso SELECT onde o mesmo irá selecionar quais campos desejados na busca da query.

Para isso especificamos os campos desejados com 1 que significa TRUE ou os campos indesejados com 0 que significa FALSE

suissacorp(mongod-3.0.6) be-mean-instagram> var query = {name: 'Pikachu'}
suissacorp(mongod-3.0.6) be-mean-instagram> var fields = {name: 1, description: 1}
suissacorp(mongod-3.0.6) be-mean-instagram> db.pokemons.find(query, fields)
{
  "_id": ObjectId("564220f0613f89ac53a7b5d0"),
  "name": "Pikachu",
  "description": "Rato elétrico bem fofinho"
}
Fetched 1 record(s) in 1ms

Operadores de Aritmética

< é $lt - less than

db.colecao.find({ "campo" : { $lt: value } } ); Retorna documentos com valores menores que value.

<= ou $lte - less than or equal

db.colecao.find({ "campo" : { $lte: value } } ); Retorna documentos com valores menores ou igual que value.

> ou $gt - greater than

db.colecao.find({ "campo" : { $gt: value } } ); Retorna documentos com valores maiores que value.

>= ou $gte - greater than or equal

db.colecao.find({ "campo" : { $gte: value } } ); Retorna documentos com valores maiores ou igual que value.

Operadores Lógicos

$or

Retorna documentos caso a cláusula OU for verdadeira, ou seja, se alguma das cláusulas forem verdadeiras

Sintaxe
{ $or : [ { campo1 : valor } , { campo2 : valor } ] }
Uso

Vamos buscar os Pokemons que possuam OU o {name: Pikachu} OU do tipo grama {type: 'grama'}.

$nor

Retorna documentos caso a cláusula negação do OU for verdadeira, ou seja, retorna apenas documentos que não satisfaçam as cláusulas.

Sintaxe
{ $nor : [ { a : 1 } , { b : 2 } ] }
Uso

$and

Retorna documentos caso a cláusula E for verdadeira, ou seja, somente se todos as cláusulas forem verdadeiras.

Sintaxe
{ $and: [ { a: 1 }, { a: { $gt: 5 } } ] }
Uso

Operadores "Existênciais"

$exists

Sintaxe
db.colecao.find( { campo : { $exists : true } } );

Retorna o objeto caso o campo exista.

Uso

Operadores de Array

Antes de iniciar essa parte e já conhecendo sobre o update, pois foi dado anteriormente que esta parte, vamos deixar todos os pokemons com 1 ataque igual.

var query = {}
var mod = {$set: {moves: ['investida']}}
var options = {multi: true}
db.pokemons.update(query, mod, options)

Pronto agora todos pokemons possuem um campo do tipo Array, para finalizar vamos adicionar 1 ataque para: Charmander, Squirtle e Bulbassauro.

var query = {name: /pikachu/i}
var mod = {$push: {moves: 'choque do trovão'}}
db.pokemons.update(query, mod)

var query = {name: /squirtle/i}
var mod = {$push: {moves: 'hidro bomba'}}
db.pokemons.update(query, mod)

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

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

$in

O operador $in retorna o(s) documento(s) que possui(em) algum dos valores passados no [Array_de_valores].

Sintaxe
{ campo : { $in : [Array_de_valores] } }
Uso

Imaginemos que precisamos buscar todos Pokemons que possuam o ataque choque do trovão, pois o investida todos já possuem.

DICA: também pode usar REGEX aqui!

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

Pronto com isso achamos apenas o Pikachu.

$nin

Retorna documentos se nenhum dos valores for encontrado.

Sintaxe
{ campo : { $nin :[ [Array_de_valores] ] } }
Uso

Podemos trazer todos Pokemons que não possuem o ataque investida.

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

Nesse caso todos, excluindo o Pikachu.

$all

Retorna documentos se todos os valores foram encontrados.

Sintaxe
{ campo : { $all :[ Array_de_valores ] } } )
Uso

Agora podemos buscar quais pokemons possuem os ataques investida e hidro bomba.

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

Dessa vez retornará apenas o Squirtle.

Operadores de Negação

$ne - not Equal

Retorna documentos se o valor não for igual.

Sintaxe
{ campo : { $ne : valor} }
Uso

Podemos agora buscar todos os pokemons que não são do tipo grama.

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

DICA: Não aceita REGEX!!!!

Error

Caso tente passar um valor como REGEX o MongoDb retornará esse erro:

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

$not

Retorna o objeto que não satisfaz a condição do campo, isso inclui documentos que não possuem o campo.

Sintaxe
{ campo : { $not : { $gt: 666 } } }
Uso

Com esse operador iremos buscar os pokemons que não tem um attack acima de 50.

var query = {attack: { $not : { $gt: 50 } } }
db.pokemons.find(query)

Percebeu que os documentos que não possuem o campo attack também retornaram e que null é menor que 50.

E podemos usar REGEX para trazer todos os pokemons que não possuam o nome Pikachu.

var query = { name : { $not : /pikachu/i } }
db.pokemons.find(query)
Filtro com Data

Usando o conhecimento sobre $and, $gte e $lt podemos realizar busca de datas.

Exemplo: Gostaria de puxar o cadastro de um pokemon que foi criado em 17/01/2016 cuja o nome seja 'Bulbassauro'.

Inserindo dados na coleção.

var pokemons = {'name':'Bulbassauro','description':'Chicote de trepadeira','type': 'grama', 'attack': 49, height: 0.4, created_at: new Date()};

db.pokemons.insert(pokemons);

WriteResult({ "nInserted" : 1 })

Depois da inserção buscaremos o campo created_at, que consta a data da criação do documento.

> var query = {$and: [{created_at: {$gte: new Date(2016, 0, 17), $lt: new Date(2016, 0, 18)}},{name:'Bulbassauro'}]};

> db.pokemons.findOne(query).pretty();
{
    "_id" : ObjectId("569bb4441b2a879aee8fb0f1"),
    "name" : "Bulbassauro",
    "description" : "Chicote de trepadeira",
    "type" : "grama",
    "attack" : 49,
    "height" : 0.4,
    "created_at" : ISODate("2016-01-17T15:33:14.893Z")
}