Eduardo Nicola F. Zagari
Sumário
MongoDB Característica Instalação Mapeamento SQL MongoDB Conexão com Banco via shell Schema Dinâmico Inserção de dados Interando sobre a coleção Sintaxe
Sumário
MongoDB Ruby Driver Instalação Conexão com banco Listagem de bases e coleções Criação/acesso de coleções Inserção de documentos Atualização de documentos Busca Índices
Sumário
Mongoid Instalação Documentos Persistência Querying Relations
Características
Armazenamento Orientado a Documentos
Suporte full-index Replicação e Alta disponibilidade Auto sharding Querying Atualizações rápidas in-place Map/Reduce GridFS
Instalando MongoDB
Download
Crie o diretório de dados
$ curl http://downloads.mongodb.org/osx/mongodb-osx-i386-x.y.z.tgz > mongo.tgz$ tar xzf mongo.tgz
$ sudo mkdir –p /data/db$ sudo chmod 777 /data/db
Instalação MongoDB
Inicie o servidor e se conecte a eleEm uma shell
Em outra shell
$ ./mongodb-XXXXXXX/bin/mongod
$ ./mongodb-XXXXXXX/bin/mongodb.foo.save( { a : 1 } ){ "_id" : ObjectId("4e46f2141373c8f77f7ee954"), "a" : 1 }
Mapeamento SQL MongoDB
Conexão com Banco via shell
Inicie a shell do MongoDB
Para trocar de base, tecle
$ /Applications/mongodb-osx-x86_64-1.8.2/bin/mongoMongoDB shell version: 1.8.2connecting to: test
> use mydbswitched to db mydb> show dbsadmin (empty)local (empty)test0.203125GB
Schema Dinâmico (Schema Free) MongoDB possui databases, collections
e índices Collections contêm documentos BSON Documentos BSON possuem campos
Sem pré-definição Sem schemas Não há a noção de “ALTER table” Na prática, é comum uma coleção possuir
estrutura de documentos homogênea, no entanto, isto não é um requisito
Inserção de Dados
> j = { name : "mongo" };{"name" : "mongo"}> t = { x : 3 };{ "x" : 3 }> db.things.save(j);> db.things.save(t);> db.things.find();{ "_id" : ObjectId("4e47fae21373c8f77f7ee955"), "name" : "mongo" }{ "_id" : ObjectId("4e47faeb1373c8f77f7ee956"), "x" : 3 }
Sem pré-definição do collection
Lazy initialization Docs com camps distintos Atribuição do campo “_id
Inserção de mais dados
> for (var i = 1; i <= 20; i++) db.things.save({x : 4, j : i});> db.things.find() { "_id" : ObjectId("4e47fae21373c8f77f7ee955"), "name" : "mongo" }{ "_id" : ObjectId("4e47faeb1373c8f77f7ee956"), "x" : 3 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee957"), "x" : 4, "j" : 1 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee958"), "x" : 4, "j" : 2 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee959"), "x" : 4, "j" : 3 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee95a"), "x" : 4, "j" : 4 }…{ "_id" : ObjectId("4e47fcb41373c8f77f7ee963"), "x" : 4, "j" : 13 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee964"), "x" : 4, "j" : 14 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee965"), "x" : 4, "j" : 15 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee966"), "x" : 4, "j" : 16 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee967"), "x" : 4, "j" : 17 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee968"), "x" : 4, "j" : 18 }has more
O Comando “it” (iterador)
…{ "_id" : ObjectId("4e47fcb41373c8f77f7ee967"), "x" : 4, "j" : 17 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee968"), "x" : 4, "j" : 18 }has more> it{ "_id" : ObjectId("4e47fcb41373c8f77f7ee969"), "x" : 4, "j" : 19 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee96a"), "x" : 4, "j" : 20 }
Acessando dados a partir de uma Query (objeto “cursor”)
> var cur = db.things.find()> while (cur.hasNext()) printjson(cur.next());{ "_id" : ObjectId("4e47fae21373c8f77f7ee955"), "name" : "mongo" }{ "_id" : ObjectId("4e47faeb1373c8f77f7ee956"), "x" : 3 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee957"), "x" : 4, "j" : 1 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee958"), "x" : 4, "j" : 2 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee959"), "x" : 4, "j" : 3 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee95a"), "x" : 4, "j" : 4 }…{ "_id" : ObjectId("4e47fcb41373c8f77f7ee965"), "x" : 4, "j" : 15 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee966"), "x" : 4, "j" : 16 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee967"), "x" : 4, "j" : 17 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee968"), "x" : 4, "j" : 18 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee969"), "x" : 4, "j" : 19 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee96a"), "x" : 4, "j" : 20 }
forEach() ao invés de while()
> db.things.find().forEach(printjson); { "_id" : ObjectId("4e47fae21373c8f77f7ee955"), "name" : "mongo" }{ "_id" : ObjectId("4e47faeb1373c8f77f7ee956"), "x" : 3 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee957"), "x" : 4, "j" : 1 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee958"), "x" : 4, "j" : 2 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee959"), "x" : 4, "j" : 3 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee95a"), "x" : 4, "j" : 4 }…{ "_id" : ObjectId("4e47fcb41373c8f77f7ee965"), "x" : 4, "j" : 15 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee966"), "x" : 4, "j" : 16 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee967"), "x" : 4, "j" : 17 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee968"), "x" : 4, "j" : 18 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee969"), "x" : 4, "j" : 19 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee96a"), "x" : 4, "j" : 20 }
Tratando cursor no estilo array
Nota: documentos até o mais alto acessado(quinto documento, no nosso caso) são todos carregados em RAM ao mesmo tempo Não apropriado para grandes coleções
> var cur = db.things.find();> printjson(cur[4]); { "_id" : ObjectId("4e47fcb41373c8f77f7ee959"), "x" : 4, "j" : 3 }
Convertendo cursor em array
Nota: cursores não são fotografias “instantâneas”
Operações feitas na coleção por usuários distintos concorrentemente podem ou não serem retornadas pelo cursor
Deve-se usar bloqueios para consultas instantâneas
> var arr = db.things.find().toArray();> arr[5];{ "_id" : ObjectId("4e47fcb41373c8f77f7ee95a"), "x" : 4, "j" : 4 }
Especificando retorno de Queries Query documents:
{a:A, b:B, …} significa “WHERE a==A AND b=BB AND …”
> db.things.find({name:"mongo"}).forEach(printjson);{ "_id" : ObjectId("4e47fae21373c8f77f7ee955"), "name" : "mongo" }
Especificando retorno de Queries
> db.things.find({x:4}).forEach(printjson);{ "_id" : ObjectId("4e47fcb41373c8f77f7ee957"), "x" : 4, "j" : 1 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee958"), "x" : 4, "j" : 2 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee959"), "x" : 4, "j" : 3 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee95a"), "x" : 4, "j" : 4 }…{ "_id" : ObjectId("4e47fcb41373c8f77f7ee965"), "x" : 4, "j" : 15 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee966"), "x" : 4, "j" : 16 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee967"), "x" : 4, "j" : 17 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee968"), "x" : 4, "j" : 18 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee969"), "x" : 4, "j" : 19 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee96a"), "x" : 4, "j" : 20 }
Especificando retorno de Queries
> db.things.find({x:4}, {j:true}).forEach(printjson);{ "_id" : ObjectId("4e47fcb41373c8f77f7ee957"), "j" : 1 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee958"), "j" : 2 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee959"), "j" : 3 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee95a"), "j" : 4 }…{ "_id" : ObjectId("4e47fcb41373c8f77f7ee965"), "j" : 15 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee966"), "j" : 16 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee967"), "j" : 17 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee968"), "j" : 18 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee969"), "j" : 19 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee96a"), "j" : 20 }
Partial Documents
findOne( ) – Syntactic Sugar
Documentos podem ser obtidos invocando-se next() sobre um cursor Tratando o cursor como um array Convertendo cursor em array etc findOne() : Açúcar Sintático
> printjson(db.things.findOne({j:4})); { "_id" : ObjectId("4e47fcb41373c8f77f7ee95a"), "x" : 4, "j" : 4 }
limit( ): limitando o retorno
> db.things.find().limit(3);{ "_id" : ObjectId("4e47fae21373c8f77f7ee955"), "name" : "mongo" }{ "_id" : ObjectId("4e47faeb1373c8f77f7ee956"), "x" : 3 }{ "_id" : ObjectId("4e47fcb41373c8f77f7ee957"), "x" : 4, "j" : 1 }
Sintaxe
Sintaxe
Sintaxe
Sintaxe
Sintaxe
MongoDB Ruby Driver
Escrito em Ruby Com uma extensão em C para
velocidade Otimizado à simplicidade Pode ser usado sozinho, além servir
de base para várias bibliotecas de mapeamento de objetos
Instalação
Para garantir a última versão do rubygems
Para instalar a gem do mongo
Para otimização de performance, instala-se também a gem bson_ext
$ gem update --system
$ gem install mongo
$ gem install bson_ext
Iniciando…
Usando a gem
Criando uma conexão
require 'rubygems' # not necessary for Ruby 1.9require 'mongo'
db = Mongo::Connection.new.db("mydb")db = Mongo::Connection.new("localhost").db("mydb")db = Mongo::Connection.new("localhost", 27017).db("mydb”)
Iniciando…
Listando todas as bases
Removendo uma base
connection = Mongo::Connection.new # (optional host/port args)connection.database_names.each { |name| puts name }connection.database_info.each { |info| puts info.inspect}
connection.drop_database('database_name’)
Iniciando
Listagem de coleções
Acessando uma coleção
Que é um alias para o método [ ]
db.collection_names.each { |name| puts name }
coll = db.collection("topicos")
coll = db[”topicos"]
Inserção de documentos
doc = {"name" => "MongoDB", "type" => "database", "count" => 1, "faculdade" => "FECOMP", "info" => {"x" => 203, "y" => 102} }coll.insert(doc)
{ "name" : "MongoDB", "type" : "database", "faculdade" : "Fecomp" "count" : 1, "info" : { x : 203, y : 102 } }
Atualização de documentos
Reescrevendo o documento
Usando um operador atômico para mudar um valor único
asaa
coll.update({"_id" => doc[:_id]}, {"$set" => {"name" => "MongoDB Ruby"}})
doc["name"] = "MongoDB Ruby"coll.update({"_id" => doc[:_id]}, doc)
Busca
Encontrando o primeiro documento
asaa
=> {"_id"=>BSON::ObjectId('4e78d41bed686f02d1000001'), "name"=>"MongoDB", "faculdade" : "Fecomp”, "info"=>{"x"=>203, "y"=>102}, "count"=>1, "type"=>"database”}
my_doc = coll.find_one()puts my_doc.inspect
Adicionando mais documentos
Contando documentos
100.times { |i| coll.insert("i" => i) }
{ "i" : value}
puts coll.count()
Busca
Usando um Cursor para obter todos os documentos
asaa
coll.find().each { |row| puts row.inspect }
Busca com Queries
Obtendo um único documento com queries
Obtendo um conjunto de documentos
asaa
coll.find("i" => 71).each { |row| puts row.inspect }
coll.find("i" => {"$gt" => 50}).each { |row| puts row.inspect }coll.find("i" => {"$gt" => 20, "$lte" => 30}).each { |row| puts row.inspect }
Busca com Queries
Queries com Expressões Regulares
Dinamicamente
asaa
coll.find("name" => /^M/).each { |row| puts row.inspect }
search_string = params['search']
#Constructor Syntaxcoll.find({"name" => Regexp.new(search_string)})
# Literal syntaxcoll.find({"name" => /#{search_string}/})
Índices
Criando índices
Explicit ”descending"
asaa
coll.create_index("i")
coll.create_index([["i", Mongo::DESCENDING]])
Índices
Criando índice geo-espacial
Query com limites
Obtendo a lista de índices de uma coleção
people.create_index([["loc", Mongo::GEO2D]])
people.find({"loc" => {"$near" => [50, 50]}}, {:limit => 20}).each do |p| puts p.inspect end
coll.index_information()
Mongoid
Object-Document-Mapper (ODM) para MongoDB
Escrito em Ruby Provém uma API familiar aos
desenvolvedores Ruby acostumados com Active Record, enquanto alavanca o poder da ausência de schema do MongoDB
Instalação
Para instalar a gem do mongoid
Arquivo de configuração mongoid.yml
Por programação
$ gem install mongoid
host: localhostdatabase: mydb
Mongoid.load!("path/to/your/mongoid.yml")
Mongoid.configure do |config| config.master = Mongo::Connection.new.db(”mydb")end
Documentos
Objetos devem incluir Mongoid::Document a fim de serem persistidos
Armazenamentoclass Person include Mongoid::Documentend
class Person include Mongoid::Document store_in :citizensend
Campos
Outros tipos: Array, BigDecimal, Boolean, Date, DateTime, Float, Hash, Integer, Range, Symbol e Time
class Person include Mongoid::Document store_in :citizens field :first_name, type: String field :middle_name, type: String field :last_name, type: Stringend
Campos: get e set
Obtém o valor do campo first_name
Atribui o valor para o campo first_name
person.first_nameperson[:first_name]person.read_attribute(:first_name)
person.first_name = ”José"person[:first_name] = ”José"person.write_attribute(:first_name, ”José")
Campos: get e set para vários campos Obtém os valores dos campos em
um hash
Atribui os valores de campos em um documento
person.attributes
Person.new(first_name: "Jean-Baptiste", middle_name: "Emmanuel")person.attributes = { first_name: "Jean-Baptiste", middle_name: "Emmanuel" }person.write_attributes( first_name: "Jean-Baptiste", middle_name: "Emmanuel")
Defaults
class Person include Mongoid::Document field :blood_alcohol_level, type: Float, default: 0.40 field :last_drink, type: Time, default: -> { 10.minutes.ago }end
Serialização de Campos customizados
class Profile include Mongoid::Document field :location, type: Pointend
class Point include Mongoid::Fields::Serializable
def deserialize(object) [ object["x"], object["y"] ] end
def serialize(object) { "x" => object[0], "y" => object[1] } endend
Campos Dinâmicos
Suporte a Campos dinâmicos Permite get, set e persistência de
atributos mesmo que um campo não tenha sido definido para ele
Não usar getters e setters Usar os métodos acessores:
person[:gender]person.read_attribute(:gender)
person[:gender] = "Male"person.write_attribute(:gender, "Male")
Acesso: Protected
class User include Mongoid::Document field :first_name, type: String field :password, type: String attr_protected :passwordend
# Ajusta atributos em uma pessoa de forma apropriadaPerson.new(first_name: "Corbin")person.attributes = { first_name: "Corbin" }person.write_attributes(first_name: "Corbin")
# Tenta ajudar os valores, levantando um erroPerson.new(first_name: "Corbin", password: "password")person.attributes = { first_name: "Corbin", password: "password" }person.write_attributes(first_name: "Corbin", password: "password")
Acesso: Accessible
class User include Mongoid::Document field :first_name, type: String field :password, type: String attr_accessible :first_nameend
# Ajusta atributos em uma pessoa de forma apropriadaPerson.new(first_name: "Corbin")person.attributes = { first_name: "Corbin" }person.write_attributes(first_name: "Corbin")
# Tenta ajudar os valores, levantando um erroPerson.new(first_name: "Corbin", password: "password")person.attributes = { first_name: "Corbin", password: "password" }person.write_attributes(first_name: "Corbin", password: "password")
Acesso: Overriding
Person.new(first_name: "Corbin") do |person| person.password = "password"end
Dirty Tracking
person = Person.firstperson.name = "Alan Garner”
# Checa para ver se o documento foi alteradoperson.changed? #=> true# Obtém um array dos nomes dos campos alteradosperson.changed #=> [ :name ]# Obtém um hash do antigo e do novo valor para cada campoperson.changes #=> { "name" => [ "Alan Parsons", "Alan Garner" ] }# Checa se um campo específico foi alteradoperson.name_changed? #=> true# Obtém as mudanças para um campo específicoperson.name_change #=> [ "Alan Parsons", "Alan Garner" ]# Obtém o valor anterior de um campoperson.name_was #=> "Alan Parsons"
class Person include Mongoid::Document field :name, type: Stringend
Limpando mudanças
person = Person.firstperson.name = "Alan Garner"
# Reinicializa o nome alterado de volta ao originalperson.reset_name!person.name #=> "Alan Parsons"
Vendo as mudanças anterioresperson = Person.firstperson.name = "Alan Garner"person.save #=> Clears out current changes.
# Vê mudanças anterioresperson.previous_changes #=> { "name" => [ "Alan Parsons", "Alan Garner" ] }
Persistência
Model.create Model.create! Model#save Model#save! Model#update_attributes Model#update_attributes! Model#update_attribute Model#delete Model#destroy Model.delete_all Model.destroy_all
Model.create
# Insere um novo poeta na base.Person.create(first_name: "Heinrich", last_name: "Heine")
# Isto também pode ser feito usando um blocoPerson.create(first_name: "Heinrich") do |doc| doc.last_name = "Heine"end
collections[”citizens"].insert({ "_id" : ..., "first_name" : "Heinrich", "last_name" : "Heine” })
Model.create!
# Insere um novo poeta na base, levantando um erro # se a validação falhar.Person.create!(first_name: "Heinrich", last_name: "Heine")
# Isto também pode ser feito usando um blocoPerson.create!(first_name: "Heinrich") do |doc| doc.last_name = "Heine"end
collections[”citizens"].insert({ "_id" : ..., "first_name" : "Heinrich", "last_name" : "Heine” })
Model#save
# Insere um novo poeta na base.person = Person.new(first_name: "Heinrich", last_name: "Heine")person.save
# Grava sem executar as validaçõesperson.save(validate: false)
# Grava os campos modificados de um documento existenteperson.first_name = "Christian Johan"person.save
# Comando de inserção de um novo documentocollections[”sitizens"].insert({ "_id" : ..., "first_name" : "Heinrich", "last_name" : "Heine” })
# Comando de atualização do doc modificadocollections["people"].update({ { "_id" : ... }, { "$set" : { "first_name" : "Christian Johan” } } })
Model#save!
# Insere um novo poeta na base.person = Person.new(first_name: "Heinrich", last_name: "Heine")person.save!
# Grava os campos modificados de um documento existenteperson.first_name = "Christian Johan"person.save!
# Comando de inserção de um novo documentocollections[”sitizens"].insert({ "_id" : ..., "first_name" : "Heinrich", "last_name" : "Heine” })
# Comando de atualização do doc modificadocollections["people"].update({ { "_id" : ... }, { "$set" : { "first_name" : "Christian Johan” } } })
Model#update_attributes
# Update the provided attributes.person.update_attributes(first_name: "Jean", last_name: "Zorg")
# Comando de atualização do doc modificadocollections[”citizens"].update({ "_id" : ..., "first_name" : ”Jean", "last_name" : ”Zorg” })
Model#update_attributes!
# Update the provided attributes.person.update_attributes!(first_name: "Jean", last_name: "Zorg")
# Comando de atualização do doc modificadocollections[”citizens"].update({ "_id" : ..., "first_name" : ”Jean", "last_name" : ”Zorg” })
Model#update_attribute
# Update the provided attributes.person.update_attribute(first_name: "Jean")
# Comando de atualização do doc modificadocollections[”citizens"].update({ "_id" : ..., "first_name" : ”Jean” })
Model#delete
person.delete
collections[”citizens"].remove("_id" : ... )
Model#destroy
person.destroy
collections[”citizens"].remove("_id" : ... )
Model#delete_all
# Apaga todos os documentos da coleçãoPerson.delete_all
# Apaga todos os documentos da coleção que satisfaçam a condiçãoPerson.delete_all(conditions: { first_name: "Heinrich" })
# Comando para apagar todoscollections[”citizens"].remove
# Comando para apagar docs que satisfaçam condiçãocollections[”citizens"].remove("first_name" : "Heinrich")
Model#destroy_all
# Apaga todos os documentos da coleçãoPerson.destroy_all
# Apaga todos os documentos da coleção que satisfaçam a condiçãoPerson.destroy_all(conditions: { first_name: "Heinrich" })
# Comando para apagar todoscollections[”citizens"].remove
# Comando para apagar docs que satisfaçam condiçãocollections[”citizens"].remove("first_name" : "Heinrich")
Atomicidade na Persistênicia
Embora Mongoid realize operações atômicas por trás da cena por default, há casos em que se deseja fazê-lo explicitamente sem persistir outros campos Model#add_to_set Model#inc Model#pull_all Model#push
Model#add_to_set
person.add_to_set(:aliases, "Bond")
collections[”citizens"].update( { "_id" : ... }, { "$addToSet" : { "aliases" : "Bond" } })
Model#inc
person.inc(:age, 1)
collections[”citizens"].update( { "_id" : ... }, { "$inc" : { "age" : 1 } })
Model#pull_all
person.pull_all(:aliases, [ "Bond", "James" ])
collections[”citizens"].update( { "_id" : ... }, { "$pullAll" : { "aliases" : [ "Bond", "James" ] } })
Model#push
person.push(:aliases, "007")
collections[”citizens"].update( { "_id" : ... }, { "$push" : { "aliases" : "007" } })
Querying
Mongoid queries são em Criteria, um wrapper de queries dinâmicas do MongoDB, que é encadeável e de avaliação “tardia”, por só acessar a base quando necessário.
Criteria – métodos de query
Model.all_in Model.also_in Criteria#and Model.any_in Model.any_of Model.asc Model.desc Criteria#distinct Model.excludes
Model.includes Model.limit Model.near Model.not_in Model.only Model.order_by Model.skip Model.where Model.without
Model.all_in | Criteria#all_in
# Traz todas as pessoas que tem Bond e 007 como aliasesPerson.all_in(aliases: [ "Bond", "007" ])
{ "aliases" : { "$all" : [ "Bond", "007" ] }}
Model.also_in | Criteria#also_in
# Traz pessoas com aliases igual a Bond ou 007Person.also_in(aliases: [ "Bond", "007" ])Person.any_in(aliases: [ "Bond" ]).also_in(aliases: [ "007" ])
{ "aliases" : { "$in" : [ "Bond", "007" ] }}
Criteria#and
# Traz todas as pessoas com last_name Jordan e first_name iniciando com dPerson.where(last_name: "Jordan").and(first_name: /^d/i)
{ "last_name" : "Jordan", "first_name" : /^d/i }
Model.any_in | Criteria#any_in
# Traz todas as pessoas com Bond e/ou 007 como aliasesPerson.any_in(aliases: [ "Bond", "007" ])Person. any_in(aliases: [ "Bond", "007", "James" ]). any_in(aliases: [ "Bond", "007" ])
{ "aliases" : { "$in" : [ "Bond", "007" ] }}
Model.any_of | Criteria#any_of
# Traz todas as pessoas com last_name Penn ou TellerPerson.any_of({ last_name: "Penn" }, { last_name: "Teller" })
{ "last_name" : { "$or" : [ { "last_name" : "Penn" }, { "last_name" : "Teller" } ] }}
Model.asc | Criteria#asc
# Retorna pessoas ordenadas por first_name e last_name em ordem alfabética crescentePerson.asc(:first_name, :last_name)Person.ascending(:first_name, :last_name)
{ "sort" : {[ [ "first_name", Mongo::ASCENDING ], [ "last_name", Mongo::ASCENDING ] ]} }
Model.where | Criteria#where
# Traz todas as pessocas com first_name EmmanuelPerson.where(first_name: "Emmanuel")
# Traz todas as pessoas com first_name Emmanuel usando Javascript.Person.where("this.first_name == 'Emmanuel'")
# Traz todas as pessoas de Berlin, onde address é “embutido”Person.where("addresses.city" => "Berlin")
{ "first_name" : "Emmanuel" }
{ "$where" : "this.first_name == 'Emmanuel'" }
{ "addresses.city" : "Berlin" }
Model.where | Criteria#where
# Exemplo de queries usando símbolo h4s para realizar critérios mais complexosPerson.where(:title.all => ["Sir"])Person.where(:age.exists => true)Person.where(:age.gt => 18)Person.where(:age.gte => 18)Person.where(:title.in => ["Sir", "Madam"])Person.where(:age.lt => 55)Person.where(:age.lte => 55)Person.where(:title.ne => "Mr")Person.where(:title.nin => ["Esquire"])Person.where(:aliases.size => 2)Person.where(:location.near => [ 22.50, -21.33 ])Person.where(:location.within => { "$center" => [ [ 50, -40 ], 1 ] })
Criteria + Modificação
Pode-se usar Mongoid criteria para se criar um seletor e usá-lo para se modificar documentos no banco
Criação
# Cria uma pessoa com title Sir e first_name Lancelot e a persistePerson.where(title: "Sir", first_name: "Lancelot").createPerson.where(title: "Sir").create(first_name: "Lancelot")
# Constrói uma pessoa com title Sir e first_name Lancelot, sem salvá-laPerson.where(title: "Sir", first_name: "Lancelot").buildPerson.where(title: "Sir").build(first_name: "Lancelot")
Atualização
# Atualiza todas as pessoas que têm last_name Oldman com um novo first_namePerson.where(last_name: "Oldman").update_all( first_name: "Pappa Gary")
Remoção
# Apaga todos os cavaleiros de Sir Arthur da basePerson.where(title: "Sir").and(king: "Arthur").delete_allPerson.where(title: "Sir", king: "Arthur").destroy_all
Finders
Métodos Finders não são encadeáveis Retornam arrays de documentos ou um
documento único (com exceções) Métodos:
Model.all Model.count Model.exists? Model.find Model.find_or_create_by Model.find_or_initialize_by Model.first Model.last
Model.all
# Encontra todas as pessoas pelas condições e opções compatíveis com MongoDBPerson.allPerson.all(conditions: { first_name: /^dur/i, "addresses.city" => "Berlin" })Person.all(conditions: { title: "Sir" }, limit: 5)Person.all(sort: [[ :first_name, :asc ]])
Model.count
# Obtém o montante de documentos que satisfazem a(s) condição(ões)Person.countPerson.count(conditions: { title: "Sir" })
Model.exists?
# Existe algum documento na base que satisfaça a(s) condição(ões)?Person.exists?Person.exists?(conditions: { title: "Sir" })
Model.find | Criteria#find
#Permite encontrar um vários documentos pelo idPerson.find(id)Person.find("4baa56f1230048567300485c")Person.where(last_name: "Black").find(id)
Person.find([id_one, id_two])Person.find(["4baa56f1230048567300485c","4baa56f1230048567300485d"])Person.where(last_name: "Black").find([ id_one, id_two ])
Model.find_or_create_by
# Encontra um documento que satisfaça a condição ou cria um novo, se não houver nada persistidoPerson.find_or_create_by(first_name: "Syd", last_name: "Vicious")
Model.find_or_initialize_by
# Encontra um documento que satisfaça a condição ou inicializa um novo, se não houver nada persistidoPerson.find_or_initialize_by(first_name: "Syd", last_name: "Vicious")
Model.first
# Encontra o primeiro documento da base que satisfaça a condição. Retorna um documento ou nil, se nada for encontrado. Pode-se definir a ordenação, a fim de se ditar qual documento deve ser retornado. Person.first(conditions: { first_name: "Syd" })Person.first(sort: [[ :first_name, :asc ]])
Model.last
# Encontra o último documento da base que satisfaça a condição. Retorna um documento ou nil, se nada for encontrado. Pode-se definir a ordenação, a fim de se ditar qual documento deve ser retornado. Person.last(conditions: { first_name: "Syd" })Person.last(sort: [[ :first_name, :asc ]])
Escopos
Mongoid permite definir escopos dentro dos modelos, a fim de se filtrar resultados de busca
São definidos no nível da Classe São encadeáveis
Named Scopes
class Person include Mongoid::Document field :occupation, type: String field :age, type: Integer
scope :rock_n_rolla, where(occupation: "Rockstar") scope :washed_up, where(:age.gt => 30) scope :over, ->(limit) { where(:age.gt => limit) }end
# Encontra todos os roqueirosPerson.rock_n_rolla
# Econtra os roqueiros que já deviam ter paradoPerson.washed_up.rock_n_rolla
# Encontra o TremendãoPerson.rock_n_rolla.over(60)
scope :current, where(:start_date.lte => Date.today)scope :current, -> { where(:start_date.lte => Date.today) }
Métodos de Classe
# Encontra todos os roqueirosPerson.rock_n_rolla
# Econtra os roqueiros que já deviam ter paradoPerson.washed_up.rock_n_rolla
# Encontra o TremendãoPerson.rock_n_rolla.over(60)
class Person include Mongoid::Document field :occupation, type: String field :age, type: Integer
class << self def rock_n_rolla where(occupation: "Rockstar") end def washed_up where(:age.gt => 30) end def over(limit) where(:age.gt => limit) end endend
Métodos de Classe e Named Scopes
Person.rock_n_rollaPerson.washed_up.rock_n_rollaPerson.rock_n_rolla.over(60)
class Person include Mongoid::Document field :occupation, type: String field :age, type: Integer
scope :washed_up, where(:age.gt => 30) scope :over, ->(limit) { where(:age.gt => limit) }
class self.rock_n_rolla where(occupation: "Rockstar") endend
Default Scopes
# Econtra os roqueiros que já deviam ter paradoPerson.washed_up
# Se quiser encontrar os mais velhos que não são roqueirosPerson.unscoped.washed_up
class Person include Mongoid::Document field :occupation, type: String field :age, type: Integer
default_scope where(occupation: "Rockstar") scope :washed_up, where(:age.gt => 30) end
Relacionamentos
Associações entre modelos no domínio e no banco.
Podem ser “embutidas” ou “referenciadas
Embedded: 1…N: “embeds_many” e “embedded_in” 1…1: “embeds_one” e “embedded_in”
Referenced: 1…N: “has_many” e “belongs_to” 1…1: “has_one” e “belongs_to” N…N: “has_and_belongs_to_many” e
“has_and_belongs_to_many”
Callbacks
after_initialize before_validation after_validation before_create around_create after_create before_update
around_update after_update before_save around_save after_save before_destroy around_destroy after_destroy
Callbacks
class Article include Mongoid::Document field :name, type: String
set_callback(:save, :before) do |document| document.generate_slug end
protected def generate_slug self.slug = name.to_permalink endend
class Article include Mongoid::Document field :name, type: String field :body, type: String field :slug, type: String
before_create :generate_slug
protected def generate_slug self.slug = name.to_permalink endend
Observers
Implementa o comportamento fora da classe
Instanciação
class ArticleObserver < Mongoid::Observer def after_save(article) Notifications.article("[email protected]", "New article", article).deliver endend
require 'article_observer'require 'audit_observer'Mongoid.observers = ArticleObserver, AuditObserverMongoid.instantiate_observers
config.mongoid.observers = :article_observer, :audit_observer
Config/application.rb
Mapeamento
class AuditObserver < Mongoid::Observer observe :account, :balance
def after_update(record) AuditTrail.new(record, "UPDATED") endend
Validations
validates_acceptance_of validates_associated validates_confirmation_of validates_exclusion_of validates_format_of validates_inclusion_of validates_length_of validates_numericality_of validates_presence_of validates_uniqueness_of
Fontes
MongoDB: Features, Quickstart and Tutorial(http://www.mongdb.com)
MongoDB Ruby Driver Tutorial (http://api.mongodb.org/ruby/current/file.TUTORIAL.html)
Mongoid (http://mongoid.org/)