Menu Docs
Página inicial do Docs
/ / /
Mongoid
/ /

Escopo

Neste guia, você pode aprender como implementar escopos em seus modelos Mongoid. Os escopos fornecem uma maneira conveniente de reutilizar critérios de filtro comuns. Para saber mais sobre como criar critérios de filtro, consulte o guia Especificar uma query de documento.

Você pode implementar escopos em seu aplicação para reduzir o código repetido se estiver aplicando os mesmos critérios à maioria das queries.

Escopos nomeados são critérios definidos na carga de classe que são referenciados por um nome fornecido. Semelhantes aos critérios de filtro, eles são carregados preguiçosamente e acorrentados.

Este exemplo define um modelo Band que inclui os seguintes escopos nomeados:

  • japanese: corresponde a documentos em que o valor do campo country é "Japan"

  • rock: corresponde a documentos em que o valor do campo genre inclui "rock"

class Band
include Mongoid::Document
field :country, type: String
field :genres, type: Array
scope :japanese, ->{ where(country: "Japan") }
scope :rock, ->{ where(:genres.in => [ "rock" ]) }
end

Em seguida, você pode consultar usando os escopos nomeados. A query a seguir usa os escopos nomeados para corresponder a documentos nos quais o valor do campo country é "Japan" e o valor do campo genre inclui "rock":

Band.japanese.rock

Você pode definir Proc objetos e blocos em escopos nomeados para que eles aceitem parâmetros e estendam a funcionalidade.

Este exemplo define um modelo Band que inclui o escopo based_in, que corresponde a documentos nos quais o valor do campo country é o valor especificado passado como um parâmetro:

class Band
include Mongoid::Document
field :name, type: String
field :country, type: String
scope :based_in, ->(country){ where(country: country) }
end

Em seguida, faça uma query usando o escopo based_in, conforme mostrado no código a seguir:

Band.based_in("Spain")

O Mongoid permite definir um escopo que sombreia um método de classe existente, conforme mostrado no exemplo a seguir:

class Band
include Mongoid::Document
def self.on_tour
true
end
scope :on_tour, ->{ where(on_tour: true) }
end

Você pode direcionar o Mongoid para gerar um erro quando um escopo substituir um método de classe existente definindo a opção de configuração scope_overwrite_exception como true.

Para saber mais sobre essa configuração, consulte o guia Configuração do aplicativo.

Os escopos padrão são úteis para casos em que você aplica os mesmos critérios à maioria das queries. Ao definir um escopo padrão, você especifica estes critérios como padrão para quaisquer queries que utilizem o modelo. Os escopos padrão retornam objetos Criteria .

Para criar um escopo padrão, você deve definir o método default_scope em sua classe de modelo.

O seguinte código define o método default_scope no modelo Band para recuperar somente documentos em que o valor de campo active seja true:

class Band
include Mongoid::Document
field :name, type: String
field :active, type: Boolean
default_scope -> { where(active: true) }
end

Em seguida, qualquer query no pré-filtro do modelo Band para documentos nos quais o valor active é true.

A especificação de um escopo padrão inicializa os campos de novos modelos para os valores fornecidos no escopo padrão se esses valores forem literais, como valores booleanos ou inteiros.

Observação

Conflitos de campo e escopo

Se você fornecer um valor padrão em uma definição de campo e no escopo padrão, o valor no escopo padrão terá precedência, como mostrado no exemplo a seguir:

class Band
include Mongoid::Document
field :name, type: String
field :on_tour, type: Boolean, default: true
default_scope ->{ where(on_tour: false) }
end
# Creates a new Band instance in which "on_tour" is "false"
Band.new

Não recomendamos usar notação de ponto para fazer referência a campos aninhados em escopos padrão. Isso pode direcionar o Mongoid a inicializar campos inesperados em novos modelos.

Por exemplo, se você definir um escopo padrão que referencia o campo tour.year , um novo modelo será inicializado com o campo tour.year em vez de um campo tour com um objeto aninhado que contém um campo year .

Ao consultar, o Mongoid interpreta a notação de ponto corretamente e corresponde a documentos nos quais um campo aninhado tem o valor especificado.

Se você definir 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. Isso é necessário para quando você altera um valor de um documento na associação que afeta sua visibilidade quando o escopo é aplicado.

Este exemplo usa os seguintes modelos:

class Label
include Mongoid::Document
field :name, type: String
embeds_many :bands
end
class Band
include Mongoid::Document
field :name, type: String
field :active, default: true
embedded_in :label
default_scope ->{ where(active: true) }
end

Suponha que você crie um modelo Label que contenha uma associação com um Band no qual o valor de active é true. Quando você atualiza o campo active para false, o Mongoid ainda o carrega, apesar do escopo padrão. Para visualizar os documentos na associação com o escopo aplicado, você deve chamar o operador reload.

O seguinte código demonstra esta sequência:

label = Label.new(name: "Hello World Records")
band = Band.new(name: "Ghost Mountain")
label.bands.push(band)
label.bands # Displays the Band because "active" is "true"
band.update_attribute(:active, false) # Updates "active" to "false"
# Displays the "Ghost Mountain" band
label.bands # => {"_id":"...","name":"Ghost Mountain",...}
# Won't display "Ghost Mountain" band after reloading
label.reload.bands # => nil

O Mongoid trata os critérios em um escopo padrão da mesma forma que quaisquer outras condições de query. Isso pode levar a um comportamento surpreendente ao usar os métodos or e nor.

Os exemplos a seguir demonstram como o Mongoid interpreta queries em modelos com um escopo padrão:

class Band
include Mongoid::Document
field :name
field :touring
field :member_count
default_scope ->{ where(touring: true) }
end
# Combines the condition to the default scope with "and"
Band.where(name: 'Infected Mushroom')
# Interpreted query:
# {"touring"=>true, "name"=>"Infected Mushroom"}
# Combines the first condition to the default scope with "and"
Band.where(name: 'Infected Mushroom').or(member_count: 3)
# Interpreted query:
# {"$or"=>[{"touring"=>true, "name"=>"Infected Mushroom"}, {"member_count"=>3}]}
# Combines the condition to the default scope with "or"
Band.or(member_count: 3)
# Interpreted query:
# {"$or"=>[{"touring"=>true}, {"member_count"=>3}]}

Para saber mais sobre operações lógicas, consulte Operações lógicas no guia Especificar uma query.

Você pode instruir o Mongoid a não aplicar o escopo padrão usando o operador unscoped, conforme mostrado nos exemplos a seguir:

# Inline example
Band.unscoped.where(name: "Depeche Mode")
# Block example
Band.unscoped do
Band.where(name: "Depeche Mode")
end

Você pode usar o método with_scope para alterar o escopo padrão em um bloco no tempo de execução.

O seguinte modelo define o escopo mexican nomeado:

class Band
include Mongoid::Document
field :country, type: String
field :genres, type: Array
scope :mexican, ->{ where(country: "Mexico") }
end

Você pode usar o método with_scope para definir o escopo nomeado mexican como o escopo padrão no tempo de execução, conforme mostrado no código a seguir:

Band.with_scope(Band.mexican) do
Band.all
end

O Mongoid trata os métodos de classe que retornam objetos Criteria como escopos. Você pode fazer query usando esses métodos de classe , como mostrado no exemplo a seguir:

class Band
include Mongoid::Document
field :name, type: String
field :touring, type: Boolean, default: true
def self.touring
where(touring: true)
end
end
Band.touring

Para saber mais sobre como personalizar seus modelos Mongoid, consulte os guias Modele seus dados .

Voltar

Especificar uma query

Nesta página