Uma Breve Introdução ao MongoDB
-
Upload
nicola-zagari -
Category
Technology
-
view
1.251 -
download
5
description
Transcript of Uma Breve Introdução ao MongoDB
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/)