Consultas
Nesta página
- Sintaxe de condição
- Sintaxe de campo
- Sintaxe MQL
- Sintaxe do operador de símbolos
- Campos
- Executar queries em campos definidos
- Queries por valores brutos
- Aliases de campo
- Documentos incorporados
- Operações lógicas
- Combinações do operador
and
Comportamentoany_of
Comportamentonone_of
Comportamentonot
Comportamento- Construção de queries incrementais
- Estratégias de fusão
- Métodos de operador suportados
- Expansão de valor do operador
- Métodos de query
- elem_match
- Projeção
only
without
- Encomenda
- Paginação
limit
skip
batch_size
- Encontrando por
_id
- Métodos de queries adicionais
- Carregamento ansioso
- Expressões regulares
- Condições nos campos
- Escopo
- Escopos nomeados
- Escopos padrão
- Substituição de escopo padrão de tempo de execução
- Métodos de classe
- queries + persistência
- Cache de consulta
- Habilitando cache de query
- Habilitando o cache de query automaticamente
- Habilitando cache de query manualmente
- Armazenando em cache o resultado de
#first
- queries assíncronas
- Configuração da execução de query assíncrona
Mongoid fornece uma query DSL rica inspirada no ActiveRecord. Uma query trivial tem a seguinte aparência:
Band.where(name: "Depeche Mode")
Uma query mais complexa utilizando várias características Mongoid pode ser como segue:
Band. where(:founded.gte => "1980-01-01"). in(name: [ "Tool", "Deftones" ]). union. in(name: [ "Melvins" ])
Os métodos de query retornam objetos Mongoid::Criteria
, que são encadeáveis e são invólucros avaliados de forma preguiçosa para a linguagem de query do MongoDB (MQL). As queries são executadas quando seus conjuntos de resultados são iterados. Por exemplo:
# Construct a Criteria object: Band.where(name: 'Deftones') # => #<Mongoid::Criteria # selector: {"name"=>"Deftones"} # options: {} # class: Band # embedded: false> # Evaluate the query and get matching documents: Band.where(name: 'Deftones').to_a # => [#<Band _id: 5ebdeddfe1b83265a376a760, name: "Deftones", description: nil>]
Métodos como first
e last
devolver os documentos individuais imediatamente. Caso contrário, a iteração de um objeto Criteria com métodos como each
ou map
recupera os documentos do servidor. to_a
pode ser usado para forçar a execução de uma query que retorna uma array de documentos, literalmente convertendo um objeto Criteria em uma array.
Quando um método de query é chamado em uma instância de Critérios, o método retorna uma nova instância de Critérios com as novas condições adicionadas às condições existentes:
scope = Band.where(:founded.gte => "1980-01-01") # => #<Mongoid::Criteria # selector: {"founded"=>{"$gte"=>"1980-01-01"}} # options: {} # class: Band # embedded: false> scope.where(:founded.lte => "2020-01-01") # => #<Mongoid::Criteria # selector: {"founded"=>{"$gte"=>"1980-01-01", "$lte"=>"2020-01-01"}} # options: {} # class: Band # embedded: false> scope # => #<Mongoid::Criteria # selector: {"founded"=>{"$gte"=>"1980-01-01"}} # options: {} # class: Band # embedded: false>
Sintaxe de condição
O Mongoid oferece suporte a três maneiras de especificar condições individuais:
Sintaxe de campo.
Sintaxe MQL.
Sintaxe do operador de símbolos.
Todas as sintaxes suportam a query de documentos incorporados usando a notação de pontos. Todas as sintaxes respeitam os tipos de campo, se o campo que está sendo consultado estiver definido na classe do modelo e nos aliases de campo.
Os exemplos nesta seção usam a seguinte definição de modelo:
class Band include Mongoid::Document field :name, type: String field :founded, type: Integer field :m, as: :member_count, type: Integer embeds_one :manager end class Manager include Mongoid::Document embedded_in :band field :name, type: String end
Sintaxe de campo
A sintaxe de query mais simples utiliza os hash Ruby básicos. As chaves podem ser símbolos ou strings e correspondem a nomes de campos em documentos MongoDB:
Band.where(name: "Depeche Mode") # => #<Mongoid::Criteria # selector: {"name"=>"Depeche Mode"} # options: {} # class: Band # embedded: false> # Equivalent to: Band.where("name" => "Depeche Mode")
Sintaxe MQL
É possível especificar um operador de MQL em qualquer campo usando a sintaxe de hash:
Band.where(founded: {'$gt' => 1980}) # => #<Mongoid::Criteria # selector: {"founded"=>{"$gt"=>1980}} # options: {} # class: Band # embedded: false> # Equivalent to: Band.where('founded' => {'$gt' => 1980})
Sintaxe do operador de símbolos
Os operadores MQL podem ser especificados como métodos em símbolos para o respectivo nome de campo, como segue:
Band.where(:founded.gt => 1980) # => #<Mongoid::Criteria # selector: {"founded"=>{"$gt"=>1980}} # options: {} # class: Band # embedded: false>
Campos
Executar queries em campos definidos
Para consultar um campo, não é necessário adicionar o campo à definição da classe de modelo. No entanto, se um campo for definido na classe de modelo, o Mongoid forçará os valores de query a corresponderem aos tipos de campo definidos ao construir a query:
Band.where(name: 2020, founded: "2020") # => #<Mongoid::Criteria # selector: {"name"=>"2020", "founded"=>2020} # options: {} # class: Band # embedded: false>
Queries por valores brutos
Se você quiser ignorar o comportamento de coerção de tipo de query do Mongoid e consultar diretamente o valor de tipo bruto no banco de dados, encapsule o valor de query em classe Mongoid::RawValue
. Isso pode ser útil ao trabalhar com dados legados.
Band.where(founded: Mongoid::RawValue("2020")) # => #<Mongoid::Criteria # selector: {"founded"=>"2020"} # options: {} # class: Band # embedded: false>
Aliases de campo
As queries levam em conta os nomes de campo de armazenamento e os aliases de campo:
Band.where(name: 'Astral Projection') # => #<Mongoid::Criteria # selector: {"n"=>"Astral Projection"} # options: {} # class: Band # embedded: false>
Como os campos id
e _id
são aliases, qualquer um pode ser utilizado para queries:
Band.where(id: '5ebdeddfe1b83265a376a760') # => #<Mongoid::Criteria # selector: {"_id"=>BSON::ObjectId('5ebdeddfe1b83265a376a760')} # options: {} # class: Band # embedded: false>
Documentos incorporados
Para corresponder aos valores de campos de documentos incorporados, use a notação de ponto:
Band.where('manager.name' => 'Smith') # => #<Mongoid::Criteria # selector: {"manager.name"=>"Smith"} # options: {} # class: Band # embedded: false> Band.where(:'manager.name'.ne => 'Smith') # => #<Mongoid::Criteria # selector: {"manager.name"=>{"$ne"=>"Smith"}} # options: {} # class: Band # embedded: false>
Observação
As queries sempre retornam instâncias de modelo de nível superior, mesmo que todas as condições estejam referenciando documentos incorporados.
Operações lógicas
O Mongoid suporta operações lógicas and
, or
, nor
e not
em objetos Criteria
. Esses métodos tomam um ou mais hash de condições ou outro objeto Criteria
como seus argumentos, com not
adicionalmente tendo uma versão livre de argumentos.
# and with conditions Band.where(label: 'Trust in Trance').and(name: 'Astral Projection') # or with scope Band.where(label: 'Trust in Trance').or(Band.where(name: 'Astral Projection')) # not with conditions Band.not(label: 'Trust in Trance', name: 'Astral Projection') # argument-less not Band.not.where(label: 'Trust in Trance', name: 'Astral Projection')
Para compatibilidade com versões anteriores do Mongoid, todos os métodos de operação lógica também aceitam arrays de parâmetros, que serão achatadas para obter os critérios. Passar arrays para operações lógicas é obsoleto e pode ser removido em uma versão futura do Mongoid.
As chamadas a seguir produzem as mesmas condições de query:
# Condition hashes passed to separate and invocations Band.and(name: 'SUN Project').and(member_count: 2) # Multiple condition hashes in the same and invocation Band.and({name: 'SUN Project'}, {member_count: 2}) # Multiple condition hashes in an array - deprecated Band.and([{name: 'SUN Project'}, {member_count: 2}]) # Condition hash in where and a scope Band.where(name: 'SUN Project').and(Band.where(member_count: 2)) # Condition hash in and and a scope Band.and({name: 'SUN Project'}, Band.where(member_count: 2)) # Scope as an array element, nested arrays - deprecated Band.and([Band.where(name: 'SUN Project'), [{member_count: 2}]]) # All produce: # => #<Mongoid::Criteria # selector: {"name"=>"SUN Project", "member_count"=>2} # options: {} # class: Band # embedded: false>
Combinações do operador
A partir do Mongoid 7.1, os operadores lógicos (and
, or
, nor
e not
) foram alterados para ter a mesma semântica que os do ActiveRecord. Para obter a semântica de or
como ela se comportou no Mongoid 7.0 e versões anteriores, use any_of
, descrito abaixo.
Quando as condições são especificadas no mesmo campo várias vezes, todas as condições são adicionadas aos critérios:
Band.where(name: 1).where(name: 2).selector # => {"name"=>"1", "$and"=>[{"name"=>"2"}]} Band.where(name: 1).or(name: 2).selector # => {"$or"=>[{"name"=>"1"}, {"name"=>"2"}]}
any_of
, none_of
, nor
e not
comportam-se da mesma forma, com not
produzindo diferentes formas de query como descrito abaixo.
Quando and
operadores lógicos, or
e nor
são usados, eles operam sobre os critérios construídos até aquele ponto e seu argumento. where
tem o mesmo significado que and
:
# or joins the two conditions Band.where(name: 'Sun').or(label: 'Trust').selector # => {"$or"=>[{"name"=>"Sun"}, {"label"=>"Trust"}]} # or applies only to the first condition, the second condition is added # to the top level as $and Band.or(name: 'Sun').where(label: 'Trust').selector # => {"$or"=>[{"name"=>"Sun"}], "label"=>"Trust"} # Same as previous example - where and and are aliases Band.or(name: 'Sun').and(label: 'Trust').selector # => {"$or"=>[{"name"=>"Sun"}], "label"=>"Trust"} # Same operator can be stacked any number of times Band.or(name: 'Sun').or(label: 'Trust').selector # => {"$or"=>[{"name"=>"Sun"}, {"label"=>"Trust"}]} # The label: Foo condition is added to the top level as $and Band.where(name: 'Sun').or(label: 'Trust').where(label: 'Foo').selector # => {"$or"=>[{"name"=>"Sun"}, {"label"=>"Trust"}], "label"=>"Foo"}
and
Comportamento
O método and
adicionará novas condições simples ao nível superior dos critérios, a menos que os critérios de recebimento já tenham uma condição nos respectivos campos, caso em que as condições serão combinadas com $and
.
Band.where(label: 'Trust in Trance').and(name: 'Astral Projection').selector # => {"label"=>"Trust in Trance Records", "name"=>"Astral Projection"} Band.where(name: /Best/).and(name: 'Astral Projection').selector # => {"name"=>/Best/, "$and"=>[{"name"=>"Astral Projection"}]}
A partir do Mongoid 7.1, especificar vários critérios no mesmo campo com and
combina todos os critérios assim especificados, enquanto em versões anteriores de condições Mongoid em um campo às vezes substituía condições previamente especificadas no mesmo campo, dependendo de qual forma de and
foi usada.
or
/nor
Behavior _----------------------
or
e nor
produzem $or
e $nor
operadores MongoDB, respectivamente, usando o receptor e todos os argumentos como operandos. Por exemplo:
Band.where(name: /Best/).or(name: 'Astral Projection') # => {"$or"=>[{"name"=>/Best/}, {"name"=>"Astral Projection"}]} Band.where(name: /Best/).and(name: 'Astral Projection'). or(Band.where(label: /Records/)).and(label: 'Trust').selector # => {"$or"=>[{"name"=>/Best/, "$and"=>[{"name"=>"Astral Projection"}]}, {"label"=>/Records/}], "label"=>"Trust"}
Se a única condição no receptor for outra or
/nor
, as novas condições são adicionadas à lista existente:
Band.where(name: /Best/).or(name: 'Astral Projection'). or(Band.where(label: /Records/)).selector # => {"$or"=>[{"name"=>/Best/}, {"name"=>"Astral Projection"}, {"label"=>/Records/}]}
Use any_of
para adicionar uma disjunção a um objeto Criteria e, ao mesmo tempo, manter todas as condições criadas até o momento.
any_of
Comportamento
any_of
adiciona uma disjunção construída de seus argumentos às condições existentes nos critérios. Por exemplo:
Band.where(label: /Trust/).any_of({name: 'Astral Projection'}, {name: /Best/}) # => {"label"=>/Trust/, "$or"=>[{"name"=>"Astral Projection"}, {"name"=>/Best/}]}
As condições são elevadas ao nível superior, se possível:
Band.where(label: /Trust/).any_of({name: 'Astral Projection'}) # => {"label"=>/Trust/, "name"=>"Astral Projection"}
none_of
Comportamento
none_of
adiciona uma disjunção negativa ("nor") construída a partir de seus argumentos para as condições existentes nos critérios. Por exemplo:
Band.where(label: /Trust/).none_of({name: 'Astral Projection'}, {name: /Best/}) # => {"label"=>/Trust/, "$nor"=>[{"name"=>"Astral Projection"}, {"name"=>/Best/}]}
not
Comportamento
not
método pode ser chamado sem argumentos, caso em que ele negará a próxima condição que é especificada. not
também pode ser chamado com uma ou mais condições de hash ou objetos Criteria
, que serão todos negados e adicionados aos critérios.
# not negates subsequent where Band.not.where(name: 'Best').selector # => {"name"=>{"$ne"=>"Best"}} # The second where is added as $and Band.not.where(name: 'Best').where(label: /Records/).selector # => {"name"=>{"$ne"=>"Best"}, "label"=>/Records/} # not negates its argument Band.not(name: 'Best').selector # => {"name"=>{"$ne"=>"Best"}}
Observação
$not
no servidor MongoDB não pode ser usado com um argumento de string. O Mongoid usa o operador $ne
para obter essa negação:
# String negation - uses $ne Band.not.where(name: 'Best').selector # => {"name"=>{"$ne"=>"Best"}} # Regexp negation - uses $not Band.not.where(name: /Best/).selector # => {"name"=>{"$not"=>/Best/}}
Da mesma forma que and
, not
negará condições individuais para critérios de campo simples. Para condições complexas e quando um campo já tem uma condição definida nele, uma vez que o servidor MongoDB só suporta o operador $not
em uma base por campo em vez de globalmente, o Mongoid emula $not
usando uma construção {'$and' => [{'$nor' => ...}]}
:
# Simple condition Band.not(name: /Best/).selector # => {"name"=>{"$not"=>/Best/}} # Complex conditions Band.where(name: /Best/).not(name: 'Astral Projection').selector # => {"name"=>/Best/, "$and"=>[{"$nor"=>[{"name"=>"Astral Projection"}]}]} # Symbol operator syntax Band.not(:name.ne => 'Astral Projection') # => #<Mongoid::Criteria # selector: {"$and"=>[{"$nor"=>[{"name"=>{"$ne"=>"Astral Projection"}}]}]} # options: {} # class: Band # embedded: false>
Se utilizar o not
com arrays ou expressões regulares, note as advertências/limitações do $not
estacionadas na documentação do servidor MongoDB.
Construção de queries incrementais
Por padrão, quando as condições são adicionadas a uma query, o Mongoid considera cada condição completa e independente de quaisquer outras condições potencialmente presentes na query. Por exemplo, chamar in
duas vezes adiciona duas condições $in
separadas:
Band.in(name: ['a']).in(name: ['b']) => #<Mongoid::Criteria selector: {"name"=>{"$in"=>["a"]}, "$and"=>[{"name"=>{"$in"=>["b"]}}]} options: {} class: Band embedded: false>
Alguns métodos de operador permitem criar a condição de forma incremental. Nesse caso, quando uma condição em um campo que usa um dos operadores suportados estiver sendo adicionada, se já houver uma condição no mesmo campo usando o mesmo operador, as expressões do operador serão combinadas de acordo com a estratégia de mesclagem especificada.
Estratégias de fusão
O Mongoid oferece três estratégias de mesclagem:
Substituir: a nova instância do operador substitui quaisquer condições existentes no mesmo campo usando o mesmo operador.
Interseção: se já houver uma condição usando o mesmo operador no mesmo campo, os valores da condição existente serão cruzados com os valores da nova condição e o resultado será armazenado como o valor do operador.
Unidade: se já houver uma condição usando o mesmo operador no mesmo campo, os valores da nova condição serão adicionados aos valores da condição existente e o resultado será armazenado como o valor do operador.
O seguinte trecho demonstra todas as estratégias, utilizando in
como o operador de exemplo:
Band.in(name: ['a']).override.in(name: ['b']) => #<Mongoid::Criteria selector: {"name"=>{"$in"=>["b"]}} options: {} class: Band embedded: false> Band.in(name: ['a', 'b']).intersect.in(name: ['b', 'c']) => #<Mongoid::Criteria selector: {"name"=>{"$in"=>["b"]}} options: {} class: Band embedded: false> Band.in(name: ['a']).union.in(name: ['b']) => #<Mongoid::Criteria selector: {"name"=>{"$in"=>["a", "b"]}} options: {} class: Band embedded: false>
A estratégia é solicitada ligando para override
, intersect
ou union
em uma instância do Criteria
. A estratégia solicitada se aplica ao próximo método de condição chamado na query. Se o próximo método de condição chamado não for compatível com estratégias de mesclagem, a estratégia será redefinida, conforme mostrado no exemplo a seguir:
Band.in(name: ['a']).union.ne(name: 'c').in(name: ['b']) => #<Mongoid::Criteria selector: {"name"=>{"$in"=>["a"], "$ne"=>"c"}, "$and"=>[{"name"=>{"$in"=>["b"]}}]} options: {} class: Band embedded: false>
Como ne
não oferece suporte a estratégias de mesclagem, a estratégia union
foi ignorada e redefinida e, quando in
foi invocado pela segunda vez, não havia nenhuma estratégia ativa.
Aviso
Atualmente, as estratégias de mesclagem pressupõem que as condições anteriores tenham sido adicionadas ao nível superior da query, mas esse nem sempre é o caso (as condições podem estar aninhadas em uma cláusula $and
). Usar estratégias de mesclagem com critérios complexos pode fazer com que queries incorretas sejam construídas. O plano é que esse mau comportamento seja corrigido no futuro.
Métodos de operador suportados
Os métodos de operador a seguir oferecem suporte a estratégias de mesclagem:
all
in
nin
O conjunto de métodos pode ser expandido em futuras versões do Mongoid. Para compatibilidade futura, invoque um método estratégico somente quando a próxima chamada de método for um operador que ofereça suporte a estratégias de mesclagem.
Observe que, no momento, as estratégias de mesclagem são aplicadas somente quando as condições são adicionadas por meio dos métodos designados. No exemplo a seguir, a estratégia de mesclagem não é aplicada porque a segunda condição é adicionada por meio de where
e não por meio de in
:
Band.in(foo: ['a']).union.where(foo: {'$in' => 'b'}) => #<Mongoid::Criteria selector: {"foo"=>{"$in"=>["a"]}, "$and"=>[{"foo"=>{"$in"=>"b"}}]} options: {} class: Band embedded: false>
Esse comportamento pode mudar em uma versão futura do Mongoid e não deve ser considerado.
Por outro lado, não importa como a query existente foi criada quando um método de operador de suporte à estratégia de mesclagem é invocado. No exemplo a seguir, a primeira condição foi adicionada por meio where
mas o mecanismo de estratégia ainda se aplica:
Band.where(foo: {'$in' => ['a']}).union.in(foo: ['b']) => #<Mongoid::Criteria selector: {"foo"=>{"$in"=>["a", "b"]}} options: {} class: Band embedded: false>
Expansão de valor do operador
Todos os métodos de operador que suportam estratégias de mesclagem usam Array
como seu tipo de valor. O Mongoid expande os tipos compatíveis com Array
, como um Range
, quando são utilizados com estes métodos de operador:
Band.in(year: 1950..1960) => #<Mongoid::Criteria selector: {"year"=>{"$in"=>[1950, 1951, 1952, 1953, 1954, 1955, 1956, 1957, 1958, 1959, 1960]}} options: {} class: Band embedded: false>
Além disso, o Mongoid historicamente envolveu valores nãoArray
em arrays, como demonstra o exemplo a seguir:
Band.in(year: 1950) => #<Mongoid::Criteria selector: {"year"=>{"$in"=>[1950]}} options: {} class: Band embedded: false>
Métodos de query
elem_match
Esse correspondente localiza documentos com campos de array em que um dos valores de array corresponde a todas as condições. Por exemplo:
class Band include Mongoid::Document field :name, type: String field :tours, type: Array end aerosmith = Band.create!(name: 'Aerosmith', tours: [ {city: 'London', year: 1995}, {city: 'New York', year: 1999}, ]) Band.elem_match(tours: {city: 'London'}).to_a # => [aerosmith]
elem_match
também funciona com associações incorporadas:
class Band include Mongoid::Document field :name, type: String embeds_many :tours end class Tour include Mongoid::Document field :city, type: String field :year, type: Integer embedded_in :band end dm = Band.create!(name: 'Depeche Mode') aerosmith = Band.create!(name: 'Aerosmith') Tour.create!(band: aerosmith, city: 'London', year: 1995) Tour.create!(band: aerosmith, city: 'New York', year: 1999) Band.elem_match(tours: {city: 'London'}).to_a # => [aerosmith]
elem_match
não funciona com associações não incorporadas porque o MongoDB não tem participações - as condições seriam adicionadas à coleção que é a origem de uma associação não incorporada em vez da coleção do alvo da associação.c
elem_match
também pode ser usado com associações recursivamente incorporadas, como mostra o exemplo a seguir:
class Tag include Mongoid::Document field :name, type: String recursively_embeds_many end root = Tag.create!(name: 'root') sub1 = Tag.new(name: 'sub1', child_tags: [Tag.new(name: 'subsub1')]) root.child_tags << sub1 root.child_tags << Tag.new(name: 'sub2') root.save! Tag.elem_match(child_tags: {name: 'sub1'}).to_a # => [root] root.child_tags.elem_match(child_tags: {name: 'subsub1'}).to_a # => [sub1]
Projeção
Mongoid fornece dois operadores de projeção: only
e without
.
only
O método only
recupera somente os campos especificados do banco de dados. Essa operação às vezes é chamada de "projeção".
class Band include Mongoid::Document field :name, type: String field :label, type: String embeds_many :tours end class Tour include Mongoid::Document field :city, type: String field :year, type: Integer embedded_in :band end band = Band.only(:name).first
Tentar referenciar atributos que não foram carregados resulta em Mongoid::Errors::AttributeNotLoaded
.
band.label #=> raises Mongoid::Errors::AttributeNotLoaded
Embora o Mongoid atualmente permita a gravação em atributos que não foram carregados, essas gravações não serão mantidas (MONGOID-4701) e, portanto, devem ser evitadas.
only
também pode ser usado com associações incorporadas:
band = Band.only(:name, 'tours.year').last # => #<Band _id: 5c59afb1026d7c034dba46ac, name: "Aerosmith"> band.tours.first # => #<Tour _id: 5c59afdf026d7c034dba46af, city: nil, year: 1995>
Observação
As versões 4.2 e inferiores do servidor permitiram projetar uma associação e os campos da associação na mesma query, da seguinte forma:
band = Band.only(:tours, 'tours.year').last
A especificação de projeção mais recente substitui a anterior. Por exemplo, a query acima era equivalente a:
band = Band.only('tours.year').last
Versões de servidor 4.4 e superior proíbem a especificação de uma associação e seus campos em projeção na mesma query.
only
pode ser especificado com associações referenciadas (has_one, has_many, has_and_belongs_to_many), mas é atualmente ignorado para associações referenciadas - todos os campos de associações referenciadas serão carregados (MONGOID-4704).
Observe que, se um documento tiver has_one
ou has_and_belongs_to_many
associações, os campos com chaves estrangeiras deverão ser incluídos na lista de atributos carregados com only
para que essas associações sejam carregadas. Por exemplo:
class Band include Mongoid::Document field :name, type: String has_and_belongs_to_many :managers end class Manager include Mongoid::Document has_and_belongs_to_many :bands end band = Band.create!(name: 'Astral Projection') band.managers << Manager.new Band.where(name: 'Astral Projection').only(:name).first.managers # => [] Band.where(name: 'Astral Projection').only(:name, :manager_ids).first.managers # => [#<Manager _id: 5c5dc2f0026d7c1730969843, band_ids: [BSON::ObjectId('5c5dc2f0026d7c1730969842')]>]
without
O oposto de only
, without
faz com que os campos especificados sejam omitidos:
Band.without(:name) # => # #<Mongoid::Criteria # selector: {} # options: {:fields=>{"name"=>0}} # class: Band # embedded: false>
Como o Mongoid requer o campo _id
para várias operações, ele (bem como seu alias id
) não pode ser omitido via without
:
Band.without(:name, :id) # => # #<Mongoid::Criteria # selector: {} # options: {:fields=>{"name"=>0}} # class: Band # embedded: false> Band.without(:name, :_id) # => # #<Mongoid::Criteria # selector: {} # options: {:fields=>{"name"=>0}} # class: Band # embedded: false>
Encomenda
O Mongoid fornece o método order
em objetos Criteria
e seu alias, order_by
, para especificar a ordem dos documentos. Esses métodos usam um hash indicando por quais campos ordenar os documentos e se devem ser usados em ordem crescente ou decrescente para cada campo.
Band.order(name: 1) # => #<Mongoid::Criteria # selector: {} # options: {:sort=>{"name"=>1}} # class: Band # embedded: false> Band.order_by(name: -1, description: 1) # => #<Mongoid::Criteria # selector: {} # options: {:sort=>{"name"=>-1, "description"=>1}} # class: Band # embedded: false> Band.order_by(name: :desc, description: 'asc') # => #<Mongoid::Criteria # selector: {} # options: {:sort=>{"name"=>-1, "description"=>1}} # class: Band # embedded: false>
A direção pode ser especificada como inteiros 1
e -1
para ascendente e descendente, respectivamente, ou como símbolos :asc
e :desc
, ou como strings "asc"
e "desc"
.
Como alternativa, order
aceita uma array de arrays de dois elementos especificando a ordem. Os nomes e as direções dos campos podem ser cadeias de caracteres ou símbolos.
Band.order([['name', 'desc'], ['description', 'asc']]) Band.order([[:name, :desc], [:description, :asc]])
Outra maneira de fornecer o pedido é utilizar os métodos #asc
e #desc
em símbolos, como segue:
Band.order(:name.desc, :description.asc)
Os argumentos podem ser fornecidos como uma string usando a sintaxe SQL:
Band.order('name desc, description asc')
Finalmente, existem asc
e desc
métodos que podem ser usados em vez de order
/order_by
:
Band.asc('name').desc('description') # => #<Mongoid::Criteria selector: {} options: {:sort=>{"name"=>1, "description"=>-1}} class: Band embedded: false>
order
podem ser encadeadas e, nesse caso, as chamadas mais antigas definem os critérios mais significativos e as mais recentes definem os menos significativos (já que em Ruby os hashes mantêm a ordem de suas chaves):
Band.order('name desc').order('description asc') # => #<Mongoid::Criteria selector: {} options: {:sort=>{"name"=>-1, "description"=>1}} class: Band embedded: false>
Às vezes, isso pode levar a resultados surpreendentes se houver escopos, incluindo o escopo padrão, que usam order
/order_by
. Por exemplo, nas seguintes bandas de trecho são ordenadas por nome primeiro porque a ordem no escopo padrão tem precedência sobre a ordem fornecida na query, devido ao escopo padrão sendo avaliado primeiro:
class Band include Mongoid::Document field :name, type: String field :year, type: Integer default_scope -> { order(name: :asc) } end Band.order(year: :desc) # => #<Mongoid::Criteria selector: {} options: {:sort=>{"name"=>1, "year"=>-1}} class: Band embedded: false>
Paginação
O Mongoid fornece os operadores de paginação limit
, skip
e batch_size
em Criteria
.
limit
limit
Define o número total de documentos a serem devolvidos por uma query:
Band.limit(5) # => # #<Mongoid::Criteria # selector: {} # options: {:limit=>5} # class: Band # embedded: false>
skip
skip
(alias: offset
) define o número de resultados da query a ignorar antes de retornar documentos. O valor limit
, se especificado, será aplicado após os documentos serem ignorados. Ao realizar a paginação, recomenda-se que skip
seja combinado com a ordenação para garantir resultados consistentes.
Band.skip(10) # => # #<Mongoid::Criteria # selector: {} # options: {:skip=>10} # class: Band # embedded: false>
batch_size
Ao executar queries grandes ou ao iterar sobre os resultados das queries com um método enumerador como Criteria#each
, o Mongoid usa automaticamente o comando getMore do MongoDB para carregar os resultados em lotes. O batch_size
padrão é 1000, mas você pode defini-lo explicitamente:
Band.batch_size(500) # => # #<Mongoid::Criteria # selector: {} # options: {:batch_size=>500} # class: Band # embedded: false>
Encontrando por _id
O Mongoid fornece o método find
em objetos Criteria
para encontrar documentos por seus valores _id
:
Band.find('5f0e41d92c97a64a26aabd10') # => #<Band _id: 5f0e41d92c97a64a26aabd10, name: "Juno Reactor">
O método find
realiza uma conversão de tipo, se necessário, do argumento para o tipo declarado no modelo que está sendo consultado para o campo _id
. Por padrão, o tipo _id
é BSON::ObjectId
, portanto a query acima é equivalente a:
Band.find(BSON::ObjectId.from_string('5f0e41d92c97a64a26aabd10')) # => #<Band _id: 5f0e41d92c97a64a26aabd10, name: "Juno Reactor">
Observação
Ao fazer query de coleções diretamente usando o driver, a conversão de tipos não é executada automaticamente:
Band.collection.find(_id: BSON::ObjectId.from_string('5f0e41d92c97a64a26aabd10')).first # => {"_id"=>BSON::ObjectId('5f0e41d92c97a64a26aabd10'), "name"=>"Juno Reactor"} Band.collection.find(_id: '5f0e41d92c97a64a26aabd10').first # => nil
O método find
pode aceitar vários argumentos ou uma array de argumentos. Em ambos os casos, cada um dos argumentos ou elementos de array é considerado um valor _id
, e os documentos com todos os valores de _id
especificados são retornados em uma array:
Band.find('5f0e41d92c97a64a26aabd10', '5f0e41b02c97a64a26aabd0e') # => [#<Band _id: 5f0e41b02c97a64a26aabd0e, name: "SUN Project", description: nil, likes: nil>, #<Band _id: 5f0e41d92c97a64a26aabd10, name: "Juno Reactor", description: nil, likes: nil>] Band.find(['5f0e41d92c97a64a26aabd10', '5f0e41b02c97a64a26aabd0e']) # => [#<Band _id: 5f0e41b02c97a64a26aabd0e, name: "SUN Project", description: nil, likes: nil>, #<Band _id: 5f0e41d92c97a64a26aabd10, name: "Juno Reactor", description: nil, likes: nil>]
Se o mesmo valor de _id
for fornecido mais de uma vez, o documento correspondente será retornado apenas uma vez:
Band.find('5f0e41b02c97a64a26aabd0e', '5f0e41b02c97a64a26aabd0e') # => [#<Band _id: 5f0e41b02c97a64a26aabd0e, name: "SUN Project", description: nil, likes: nil>]
Os documentos retornados não são ordenados e podem ser retornados em uma ordem diferente da ordem dos valores _id
fornecidos, conforme ilustrado nos exemplos acima.
Se qualquer um dos valores _id
não for encontrado no banco de dados, o comportamento de find
dependerá do valor da opção de configuração raise_not_found_error
. Se a opção estiver definida como true
, find
gera Mongoid::Errors::DocumentNotFound
se algum dos _id
s não for encontrado. Se a opção estiver definida como false
e find
receber um único _id
para localizar e não houver nenhum documento correspondente, find
retornará nil
. Se a opção estiver definida como false
e find
receber uma array de ids para localizar e alguns não forem encontrados, o valor de retorno será uma array de documentos que foram encontrados (que podem estar vazios se nenhum documento for encontrado).
Métodos de queries adicionais
O Mongoid também possui alguns métodos úteis sobre critérios.
(operação) | Exemplo | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Obtenha o número total de documentos correspondentes a um filtro ou o número total de documentos em uma coleção. Observe que isso sempre atingirá o banco de dados para a contagem. A partir do Mongoid 7.2, o |
| ||||||||||||||||
Obtenha um número aproximado de documentos na coleção usando os metadados da coleção. O |
| ||||||||||||||||
Obtenha uma lista de valores distintos para um único campo. Observe que isso sempre atingirá o banco de dados para os valores distintos. Este método aceita a notação de ponto, permitindo assim referenciar campos em associações incorporadas. Este método respeita :ref:'field aliases <field-aliases>', incluindo os definidos em documentos incorporados. |
| ||||||||||||||||
Iterar sobre todos os documentos correspondentes nos critérios. |
| ||||||||||||||||
Determinar se existem documentos correspondentes. Retornará verdadeiro se houver 1 ou mais.
|
| ||||||||||||||||
Obter o quinto documento para os critérios fornecidos. Este método adiciona automaticamente uma classificação em _id se nenhuma classificação for fornecida. |
| ||||||||||||||||
Obter o quinto documento para os critérios fornecidos ou gere um erro se não existir nenhum. Este método adiciona automaticamente uma classificação em _id se nenhuma classificação for fornecida. |
| ||||||||||||||||
Encontre um documento pelos atributos fornecidos. Se não for encontrado, gere um erro ou retorne nulo dependendo do valor da opção de configuração
|
| ||||||||||||||||
Encontre um documento pelos set fornecidos e, se não for encontrado, crie e retorne um documento recém-persistente. Observe que os conjuntos fornecidos nos argumentos desse método substituirão qualquer conjunto em "create_with". |
| ||||||||||||||||
Encontre um documento pelos atributos fornecidos e, se não encontrado, devolva um novo. |
| ||||||||||||||||
Encontra um único documento de acordo com os critérios fornecidos. Obtenha uma lista de documentos passando um argumento de limite. Este método adiciona automaticamente uma classificação em _id. Isso pode causar problemas de desempenho; portanto, se a classificação não for desejável, o Critério #take poderá ser usado em seu lugar. |
| ||||||||||||||||
Encontra um único documento de acordo com os critérios fornecidos ou gera um erro se nenhum for encontrado. Este método adiciona automaticamente uma classificação em _id se nenhuma classificação for fornecida. Isso pode causar problemas de desempenho, portanto, se a classificação for indesejável, Critérios#take! podem ser usados. |
| ||||||||||||||||
Encontre o primeiro documento pelos atributos fornecidos e, se não for encontrado, crie e retorne um novo documento persistente. |
| ||||||||||||||||
Encontre o primeiro documento pelos atributos fornecidos e, se não for encontrado, crie e retorne um novo documento persistente usando |
| ||||||||||||||||
Encontre o primeiro documento pelos atributos fornecidos e, se não encontrado, devolva um novo. |
| ||||||||||||||||
Encontre documentos para uma expressão JavaScript fornecida; como opção, use as variáveis especificadas adicionadas ao escopo da avaliação. O argumento do escopo é aceito no MongoDB 4.2 e versões inferiores.
Preferir $expr terminado |
| ||||||||||||||||
Obtenha o quarto documento para os critérios fornecidos. Este método adiciona automaticamente uma classificação em _id se nenhuma classificação for fornecida. |
| ||||||||||||||||
Obtenha o quarto documento para os critérios fornecidos ou gere um erro se não existir nenhum. Este método adiciona automaticamente uma classificação em _id se nenhuma classificação for fornecida. |
| ||||||||||||||||
Igual à contagem, mas armazena em cache as chamadas subsequentes ao banco de dados |
| ||||||||||||||||
Obtenha os valores de um documento para os campos fornecidos. Retorna zero para campos não definidos e para campos inexistentes. Esse método não aplica uma classificação aos documentos, portanto, não necessariamente retornará os valores do primeiro documento. Este método aceita a notação de ponto, permitindo assim referenciar campos em associações incorporadas. Este método respeita :ref:'field aliases <field-aliases>', incluindo os definidos em documentos incorporados. |
| ||||||||||||||||
Obtenha todos os valores para o campo fornecido. Retorna nulo para campos não definidos e para campos inexistentes. Este método aceita a notação de ponto, permitindo assim referenciar campos em associações incorporadas. Este método respeita :ref:'field aliases <field-aliases>', incluindo os definidos em documentos incorporados. |
| ||||||||||||||||
Define a preferência de leitura para os critérios. |
| ||||||||||||||||
Obtenha o segundo documento para os critérios fornecidos. Este método adiciona automaticamente uma classificação em _id se nenhuma classificação for fornecida. |
| ||||||||||||||||
Obtenha o segundo documento para os critérios fornecidos ou gere um erro se não existir nenhum. Este método adiciona automaticamente uma classificação em _id se nenhuma classificação for fornecida. |
| ||||||||||||||||
Obtenha o penúltimo documento de acordo com os critérios fornecidos. Este método adiciona automaticamente uma classificação em _id se nenhuma classificação for fornecida. |
| ||||||||||||||||
Obtenha o penúltimo documento de acordo com os critérios fornecidos ou gere um erro se não existir nenhum. Este método adiciona automaticamente uma classificação em _id se nenhuma classificação for fornecida. |
| ||||||||||||||||
Obtenha uma lista de n documentos do banco de dados ou apenas um se nenhum parâmetro for fornecido. Este método não aplica uma classificação aos documentos, portanto pode retornar documentos diferentes de #first e #last. |
| ||||||||||||||||
Obtenha um documento do banco de dados ou gere um erro se não existir nenhum. Este método não aplica uma classificação aos documentos, portanto pode retornar documentos diferentes de #first e #last. |
| ||||||||||||||||
Obtenha um mapeamento de valores para contagens para o campo fornecido. Este método aceita a notação de ponto, permitindo assim referenciar campos em associações incorporadas. Este método respeita :ref:'field aliases <field-aliases>', incluindo os definidos em documentos incorporados. |
| ||||||||||||||||
Obtenha o terceiro documento para os critérios fornecidos. Este método adiciona automaticamente uma classificação em _id se nenhuma classificação for fornecida. |
| ||||||||||||||||
Obtenha o terceiro documento para os critérios fornecidos ou gere um erro se não existir nenhum. Este método adiciona automaticamente uma classificação em _id se nenhuma classificação for fornecida. |
| ||||||||||||||||
Obtenha o penúltimo documento de acordo com os critérios fornecidos. Este método adiciona automaticamente uma classificação em _id se nenhuma classificação for fornecida. |
| ||||||||||||||||
Obtenha o penúltimo documento para os critérios fornecidos ou gere um erro se nenhum existir. Este método adiciona automaticamente uma classificação em _id se nenhuma classificação for fornecida. |
|
Carregamento ansioso
O Mongoid fornece uma facilidade para carregar documentos de associações para evitar o problema n+1 ao iterar sobre documentos com acesso de associação. A carga ávida é suportada em todas as associações, com exceção das associações polimórficas belongs_to
.
class Band include Mongoid::Document has_many :albums end class Album include Mongoid::Document belongs_to :band end Band.includes(:albums).each do |band| p band.albums.first.name # Does not hit the database again. end
Expressões regulares
MongoDB e Mongoid permitem fazer query de documentos por expressões regulares.
Dadas as seguintes definições de modelo:
class Band include Mongoid::Document field :name, type: String field :description, type: String end Band.create!(name: 'Sun Project', description: "Sun\nProject")
...podemos fazer queries utilizando expressões regulares Ruby de forma natural:
Band.where(name: /project/i).first # => #<Band _id: 5dc9f7d5ce4ef34893354323, name: "Sun Project", description: "Sun\nProject">
Também é possível fazer query usando a sintaxe PCRE construindo BSON::Regexp::Raw
objetos explicitamente:
Band.where(description: /\AProject/).first # => #<Band _id: 5dc9f7d5ce4ef34893354323, name: "Sun Project", description: "Sun\nProject"> Band.where(description: BSON::Regexp::Raw.new('^Project')).first # => nil Band.where(description: BSON::Regexp::Raw.new('^Project', 'm')).first # => #<Band _id: 5dc9f7d5ce4ef34893354323, name: "Sun Project", description: "Sun\nProject">
Condições nos campos
Quando uma condição utiliza um campo definido no modelo, o valor que está sendo especificado na condição é convertido de acordo com as regras do campo, se houver. Por exemplo, considere a seguinte definição de modelo que contém um campo Time
, um campo Date
e um campo Object
implícito, e também intencionalmente não define um campo chamado deregistered_at
:
class Voter include Mongoid::Document field :born_on, type: Date field :registered_at, type: Time field :voted_at end
As queries nos campos born_on
e registered_at
utilizando valores Date
e Time
, respectivamente, são diretas:
Voter.where(born_on: Date.today).selector # => {"born_on"=>2020-12-18 00:00:00 UTC} Voter.where(registered_at: Time.now).selector # => {"registered_at"=>2020-12-19 04:33:36.939788067 UTC}
Mas observe as diferenças no comportamento ao fornecer uma instância do Date
em todos os cenários possíveis:
Voter.where(born_on: Date.today).selector # => {"born_on"=>2020-12-18 00:00:00 UTC} Voter.where(registered_at: Date.today).selector # => {"registered_at"=>2020-12-18 00:00:00 -0500} Voter.where(voted_at: Date.today).selector # => {"voted_at"=>Fri, 18 Dec 2020} Voter.where(deregistered_at: Date.today).selector # => {"deregistered_at"=>2020-12-18 00:00:00 UTC}
Ao usar o campo registered_at
que é do tipo Time
, a data foi interpretada como sendo na hora local (de acordo com o zona configurada). Ao utilizar o campo born_on
que é do tipo Date
, a data foi interpretada para estar em UTC. Ao usar o campo voted_at
que foi definido sem um tipo (portanto, implicitamente como um Object
), a data foi usada sem modificações na query construída. Ao usar um campo inexistente deregistered_at
a data foi interpretada como sendo em UTC e convertida em uma hora, correspondendo ao comportamento de fazer query de um campo Date
.
Escopo
Os escopos fornecem uma maneira conveniente de reutilizar critérios comuns com mais sintaxe de estilo de domínio comercial.
Escopos nomeados
Os escopos nomeados são simplesmente critérios definidos na carga de classe que são referenciados por um nome fornecido. Assim como os critérios normais, eles são preguiçosos e acorrentados.
class Band include Mongoid::Document field :country, type: String field :genres, type: Array scope :english, ->{ where(country: "England") } scope :rock, ->{ where(:genres.in => [ "rock" ]) } end Band.english.rock # Get the English rock bands.
Escopos nomeados podem levar procs e blocos para aceitar parâmetros ou estender a funcionalidade.
class Band include Mongoid::Document field :name, type: String field :country, type: String field :active, type: Boolean, default: true scope :named, ->(name){ where(name: name) } scope :active, ->{ where(active: true) do def deutsch tap do |scope| scope.selector.store("origin" => "Deutschland") end end end } end Band.named("Depeche Mode") # Find Depeche Mode. Band.active.deutsch # Find active German bands.
Por padrão, o Mongoid permite definir um escopo que sombrearia um método de classe existente, como mostra o exemplo a seguir:
class Product include Mongoid::Document def self.fresh true end scope :fresh, ->{ where(fresh: true) } end
Para que o Mongoid gere um erro quando um escopo substituiria um método de classe existente, defina a opção de configuração scope_overwrite_exception
como true
.
Escopos padrão
Os escopos padrão podem ser úteis quando você se encontra aplicando os mesmos critérios à maioria das queries e deseja especificar esses critérios como padrão. Escopos padrão são procs que retornam objetos de critérios.
class Band include Mongoid::Document field :name, type: String field :active, type: Boolean default_scope ->{ where(active: true) } end Band.each do |band| # All bands here are active. end
Especificar um escopo padrão também inicializa os campos de novos modelos para os valores fornecidos no escopo padrão, se os valores forem literais simples:
class Band include Mongoid::Document field :name, type: String field :active, type: Boolean field :num_tours, type: Integer default_scope ->{ where(active: true, num_tours: {'$gt' => 1}) } end # active is set, num_tours is not set Band.new # => #<Band _id: 5c3f7452ce4ef378295ca5f5, name: nil, active: true, num_tours: nil>
Observe que, se um valor padrão for fornecido na definição de campo e no escopo padrão, o valor no escopo padrão terá precedência:
class Band include Mongoid::Document field :name, type: String field :active, type: Boolean, default: true default_scope ->{ where(active: false) } end Band.new # => #<Band _id: 5c3f74ddce4ef3791abbb088, name: nil, active: false>
Como um escopo padrão inicializa campos em novos modelos conforme descrito acima, definir um escopo padrão com uma chave pontilhada e um valor literal simples, embora possível, não é recomendado:
class Band include Mongoid::Document field :name, type: String field :tags, type: Hash default_scope ->{ where('tags.foo' => 'bar') } end Band.create! # => Created document: {"_id"=>BSON::ObjectId('632de48f3282a404bee1877b'), "tags.foo"=>"bar"} Band.create!(tags: { 'foo' => 'bar' }) # => Created document: {"_id"=>BSON::ObjectId('632de4ad3282a404bee1877c'), "tags.foo"=>"bar", "tags"=>{"foo"=>"bar"}} Band.all.to_a # => [ #<Band _id: 632de4ad3282a404bee1877c, tags: {"foo"=>"bar"}> ]
O Mongoid 8 permite que chaves pontilhadas sejam usadas no Mongoid e, ao criar um documento, o escopo é adicionado como uma chave pontilhada nos atributos:
Band.new.attribute # => {"_id"=>BSON::ObjectId('632de97d3282a404bee1877d'), "tags.foo"=>"bar"}
Por outro lado, ao fazer query, o Mongoid procura um documento incorporado:
Band.create! # => Created document: {"_id"=>BSON::ObjectId('632de48f3282a404bee1877b'), "tags.foo"=>"bar"} Band.where # => #<Mongoid::Criteria selector: {"tags.foo"=>"bar"} options: {} class: Band embedded: false> # This looks for something like: { tags: { "foo" => "bar" } } Band.count # => 0
Uma solução alternativa é definir o escopo padrão como uma query complexa:
class Band include Mongoid::Document field :name, type: String field :tags, type: Hash default_scope ->{ where('tags.foo' => {'$eq' => 'bar'}) } end Band.create!(tags: { hello: 'world' }) Band.create!(tags: { foo: 'bar' }) # does not add a "tags.foo" dotted attribute Band.count # => 1
Você pode dizer ao Mongoid que não aplique o escopo padrão usando unscoped
, que pode ser embutido ou ter um bloco.
Band.unscoped.where(name: "Depeche Mode") Band.unscoped do Band.where(name: "Depeche Mode") end
Você também pode dizer ao Mongoid para aplicar explicitamente o escopo padrão novamente mais tarde para garantir que ele esteja sempre lá.
Band.unscoped.where(name: "Depeche Mode").scoped
Se estiver usando um escopo padrão em um modelo que faz parte de uma associação, será necessário recarregar a associação para que o escopo seja reaplicado. É importante observar que, se você alterar um valor de um documento na associação, isso afetará sua visibilidade dentro da associação com escopo.
class Label include Mongoid::Document embeds_many :bands end class Band include Mongoid::Document field :active, default: true embedded_in :label default_scope ->{ where(active: true) } end label.bands.push(band) label.bands # [ band ] band.update_attribute(:active, false) label.bands # [ band ] Must reload. label.reload.bands # []
Observação
Depois que o escopo padrão for aplicado, ele não será mais distinguido de outras condições de query. Isso pode levar a um comportamento surpreendente ao usar os operadores or
e nor
em particular:
class Band include Mongoid::Document field :name field :active field :touring default_scope ->{ where(active: true) } end Band.where(name: 'Infected Mushroom') # => # #<Mongoid::Criteria # selector: {"active"=>true, "name"=>"Infected Mushroom"} # options: {} # class: Band # embedded: false> Band.where(name: 'Infected Mushroom').or(touring: true) # => # #<Mongoid::Criteria # selector: {"$or"=>[{"active"=>true, "name"=>"Infected Mushroom"}, {"touring"=>true}]} # options: {} # class: Band # embedded: false> Band.or(touring: true) # => # #<Mongoid::Criteria # selector: {"$or"=>[{"active"=>true}, {"touring"=>true}]} # options: {} # class: Band # embedded: false>
No último exemplo, você pode esperar que as duas condições (active: true
e touring: true
) sejam combinadas com um $and
, mas como a classe Band
já tem o escopo aplicado a ela, ela se torna uma das ramificações de disjunção do or
.
Substituição de escopo padrão de tempo de execução
Você pode usar o método with_scope
para alterar o escopo padrão em um bloco no tempo de execução:
class Band include Mongoid::Document field :country, type: String field :genres, type: Array scope :english, ->{ where(country: "England") } end criteria = Band.with_scope(Band.english) do Band.all end criteria # => # #<Mongoid::Criteria # selector: {"country"=>"England"} # options: {} # class: Band # embedded: false>
Observação
Se as chamadas with_scope forem aninhadas, quando o bloqueio with_scope aninhado concluir o Mongoid 7 define o escopo atual como nulo em vez do escopo pai. O Mongoid 8 definirá o escopo atual para o escopo pai correto. Para obter o comportamento Mongoid 8 no Mongoid 7.4 e superior, defina a opção global Mongoid.broken_scoping
como falsa.
Métodos de classe
Métodos de classe em modelos que retornam objetos de critérios também são tratados como escopos, e também podem ser encadeados.
class Band include Mongoid::Document field :name, type: String field :active, type: Boolean, default: true def self.active where(active: true) end end Band.active
queries + persistência
O Mongoid suporta operações de persistência fora dos critérios em uma capacidade leve para quando você deseja realizar inserções, atualizações e exclusões de vários documentos de forma expressiva.
Aviso
As condições de pedido e paginação dos critérios, incluindo order
, limit
, offset
e batch_size
, serão ignoradas nas seguintes operações.
(operação) | Exemplo | ||
---|---|---|---|
Crie um documento recentemente persistido. |
| ||
Crie um documento recentemente persistido e gere uma exceção em caso de falha de validação. |
| ||
Crie um novo documento (não salvo). |
| ||
Atualize os atributos do primeiro documento correspondente. |
| ||
Atualizar atributos de todos os documentos correspondentes. |
| ||
Executar um $addToSet em todos os documentos correspondentes. |
| ||
Execute um $bit em todos os documentos correspondentes. |
| ||
Executar um $inc em todos os documentos correspondentes. |
| ||
Executar um $pop em todos os documentos correspondentes. |
| ||
Executar um $pull em todos os documentos correspondentes. |
| ||
Execute um $pullAll em todos os documentos correspondentes. |
| ||
Execute um $push em todos os documentos correspondentes. |
| ||
Execute uma $push com $each em todos os documentos correspondentes. |
| ||
Executar um $rename em todos os documentos correspondentes. |
| ||
Executar um $set em todos os documentos correspondentes. |
| ||
Executar um $unset em todos os documentos correspondentes. |
| ||
Exclui todos os documentos correspondentes no banco de dados. |
| ||
Exclui todos os documentos correspondentes no banco de dados enquanto executa callbacks para todos. Isso carrega todos os documentos na memória e pode ser uma operação cara. |
|
Cache de consulta
As versões 2.14 e superiores do driver Ruby MongoDB fornecem funcionalidade de cache de consulta. Quando ativado, o cache de query salva os resultados das querys de busca e agregação executadas anteriormente e os reutiliza no futuro, em vez de realizar as querys novamente, aumentando o desempenho do aplicativo e reduzindo a carga do banco de dados.
Consulte a documentação do cache de consulta do driver para obter detalhes sobre o comportamento do cache de query de driver.
O restante desta seção presume que o driver 2.14.0 ou posterior está sendo usado.
Habilitando cache de query
O cache de query pode ser habilitado usando o namespace do driver ou o namespace do Mongoid.
Habilitando o cache de query automaticamente
O MongoDB Ruby Driver fornece middleware para ativar automaticamente o cache de query para solicitações web do Rack e execuções de tarefas do ActiveJob. Consulte a seção Query Cache Rack Middleware na página de configuração para obter instruções.
Observe que o Query Cache Middleware não se aplica ao código executado fora de solicitações da web e/ou trabalhos.
Habilitando cache de query manualmente
Para ativar o cache de query manualmente para um segmento de código, use:
Mongo::QueryCache.cache do # ... end
O Cache de Query também pode ser ativado e desativado explicitamente, embora seja recomendável usar o formulário de bloqueio descrito acima:
begin Mongo::QueryCache.enabled = true # ... ensure Mongo::QueryCache.enabled = false end
Armazenando em cache o resultado de #first
A chamada do método first
em uma classe de modelo impõe uma classificação crescente pelo campo _id
na query subjacente. Isso pode produzir um comportamento inesperado com o cache de query.
Por exemplo, ao chamar all
em uma classe de modelo e depois first
, seria de se esperar que a segunda query usasse os resultados em cache da primeira. No entanto, devido à classificação imposta na segunda query, ambos os métodos farão a query do banco de dados e armazenarão separadamente seus resultados em cache.
Band.all.to_a #=> Queries the database and caches the results Band.first #=> Queries the database again because of the sort
Para usar os resultados em cache, ligue para all.to_a.first
na classe de modelo.
queries assíncronas
O Mongoid permite executar queries de banco de dados de forma assíncrona em segundo plano. Isso pode ser benéfico quando houver necessidade de obter documentos de diferentes coleções.
Para agendar uma query assíncrona, chame o método load_async
em um Criteria
:
class PagesController < ApplicationController def index @active_bands = Band.where(active: true).load_async @best_events = Event.best.load_async @public_articles = Article.where(public: true).load_async end end
No exemplo acima, três queries serão agendadas para execução assíncrona. Os resultados das queries podem ser acessados como de costume:
<ul> <%- @active_bands.each do -%> <li><%= band.name %></li> <%- end -%> </ul>
Mesmo se uma query estiver programada para execução assíncrona, ela poderá ser executada de forma sincronizada na conversa do chamador. Existem três cenários possíveis dependendo de quando os resultados da query estiverem sendo acessados:
Se a tarefa assíncrona agendada já tiver sido executada, os resultados serão retornados.
Se a tarefa tiver sido iniciada, mas ainda não tiver sido concluída, o tópico do chamador bloqueará até que a tarefa seja concluída.
Se a tarefa ainda não tiver sido iniciada, ela será removida da fila de execução e a query será executada de forma síncrona na thread do chamador.
Observação
Embora o método load_async
devolva um objeto Criteria
, você não deve realizar nenhuma operação neste objeto, exceto acessar os resultados da query. A query está programada para execução imediatamente após ligar para load_async
, portanto, alterações posteriores no objeto Criteria
podem não ser aplicadas.
Configuração da execução de query assíncrona
As queries assíncronas são desativadas por padrão. Quando as queries assíncronas estiverem desativadas, load_async
executará uma query imediatamente na thread atual, bloqueando conforme necessário. Portanto, chamando load_async
nos critérios, nesse caso, é praticamente o equivalente de chamar to_a
para forçar a execução da query.
Para habilitar a execução de query assíncrona, as seguintes opções de configuração devem ser definidas:
development: ... options: # Execute asynchronous queries using a global thread pool. async_query_executor: :global_thread_pool # Number of threads in the pool. The default is 4. # global_executor_concurrency: 4