Operações CRUD
Nesta página
- Salvando documentos
- Padrão
- Atômico
- Recarregando
- A recarregar documentos não guardados
- Acessando valores de campo
- Getters e Setters
- Getters e setters personalizados
read_attribute
&write_attribute
- Acesso ao hash
- Gravações de atributos em massa
- rastreamento sujo
- Exibindo alterações
- Redefinindo alterações
- Persistência
- Visualizando alterações anteriores
- Atualizando campos de contêiner
- Documentos somente leitura
- Substituição
readonly?
Salvando documentos
O Mongoid oferece suporte a todas as operações CRUD esperadas para quem está familiarizado com outros mapeadores Ruby, como Active Record ou Data Mapper. O que distingue o Mongoid de outros mapeadores para o MongoDB é que as operações gerais de persistência realizam atualizações atômicas apenas nos campos que foram alterados, em vez de gravar o documento inteiro no banco de dados a cada vez.
As seções de persistência fornecerão exemplos sobre qual operação do banco de dados é executada ao executar o comando documentado.
Padrão
Os métodos de persistência padrão do Mongoid vêm na forma de métodos comuns encontrados em outros frameworks de mapeamento. A tabela abaixo mostra exemplos de todas as operações padrão.
(operação) | Exemplo | |||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Retorna os atributos do documento como um ``Hash`` com chaves de string e seus valores no formato Mongoized (ou seja, a maneira como são armazenados no banco de dados). O hash de atributos também contém os atributos de todos os documentos incorporados, bem como seus documentos incorporados, etc. Se uma associação incorporada estiver vazia, sua chave não aparecerá no hash retornado. |
| |||||||||||||||||||||||
Insira um documento ou vários documentos no banco de dados, criando um erro se ocorrer um erro de servidor ou validação. Passe um hash de atributos para criar um documento com os atributos especificados ou uma array de hashes para criar vários documentos. Se um único hash for passado, o documento correspondente será retornado. Se uma array de hashes for passada, uma array de documentos correspondentes aos hashes será retornada. Se um bloco for dado a Se houver um problema ao salvar qualquer um dos documentos, como um erro de validação ou um erro de servidor, será gerada uma exceção e, consequentemente, nenhum dos documentos será retornado. No entanto, se uma array de hashes tiver sido passada e os documentos anteriores tiverem sido salvos com êxito, esses documentos permanecerão no banco de dados. |
| |||||||||||||||||||||||
Solicite um documento ou vários documentos e, se as validações passarem, insira-os no banco de dados.
Se algum erro de validação for encontrado, o respectivo documento não será inserido, mas retornado junto com documentos inseridos. Usar |
| |||||||||||||||||||||||
Salve os atributos alterados no banco de dados atomicamente ou insira o documento se for novo. Gera uma exceção se as validações falharem ou se houver um erro no servidor. Retorna verdadeiro se os atributos alterados foram salvos; caso contrário, ocorre uma exceção. |
| |||||||||||||||||||||||
Salve os atributos alterados no banco de dados atomicamente, ou insira o documento se for novo. Retorna verdadeiro se os atributos alterados foram salvos. Retornará falso se houver algum erro de validação. Cria uma exceção se o documento passou na validação, mas ocorreu um erro de servidor durante o salvamento. Passar Passar |
| |||||||||||||||||||||||
Atualize os atributos do documento no banco de dados. Retornará verdadeiro se a validação for aprovada; caso contrário, retornará falso. |
| |||||||||||||||||||||||
Atualize os atributos do documento no banco de dados e crie um erro se a validação falhar. |
| |||||||||||||||||||||||
Atualize um único atributo, ignorando validações. |
| |||||||||||||||||||||||
Executa uma substituição MongoDB por upsert no documento. Se o documento existir no banco de dados e o |
| |||||||||||||||||||||||
Atualize o carimbo de data/hora updated_at do documento, opcionalmente com um campo de hora extra fornecido. Isso transmitirá o toque a todos
Tentar tocar em um documento destruído aumentará |
| |||||||||||||||||||||||
Exclui o documento do banco de dados sem executar callbacks. Se o documento não for persistente, o Mongoid tentará excluir do banco de dados qualquer documento com o mesmo |
| |||||||||||||||||||||||
Exclui o documento do banco de dados durante a execução de chamadas de respostas de destruição. Se o documento não for persistente, o Mongoid tentará excluir do banco de dados qualquer documento com o mesmo |
| |||||||||||||||||||||||
Exclui todos os documentos do banco de dados sem executar retornos de chamada. |
| |||||||||||||||||||||||
Exclui todos os documentos do banco de dados durante a execução de callbacks. Esta é uma operação potencialmente cara, pois todos os documentos serão carregados na memória. |
|
O Mongoid fornece os seguintes atributos relacionados à persistência:
Atributo | Exemplo | |||||||
---|---|---|---|---|---|---|---|---|
Devoluções |
| |||||||
Devoluções |
|
Atômico
O Mongoid expõeoperadores de atualização do MongoDB como métodos em documentos Mongoid. Quando esses métodos são usados, os retornos de chamada não são invocados e as validações não são realizadas. Os operadores de atualização suportados são:
(operação) | Exemplo | |||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Executa um $addToSet atômico no campo. |
| |||||||||||||||||||||||||||||||||||||||||||
Executa um $bit atômico no campo. |
| |||||||||||||||||||||||||||||||||||||||||||
Executa um $inc atômico no campo. |
| |||||||||||||||||||||||||||||||||||||||||||
Executa um $pop atômico no campo. |
| |||||||||||||||||||||||||||||||||||||||||||
Executa um $pull atômico no campo. |
| |||||||||||||||||||||||||||||||||||||||||||
Executa um $pullAll atômico no campo. |
| |||||||||||||||||||||||||||||||||||||||||||
Executa uma $push atômica no campo. |
| |||||||||||||||||||||||||||||||||||||||||||
Executa um $rename atômico no campo. |
| |||||||||||||||||||||||||||||||||||||||||||
Atualiza um atributo na instância do modelo e, se a instância já estiver persistente, executa um $set atômico no campo, ignorando validações.
|
| |||||||||||||||||||||||||||||||||||||||||||
Executa um $unset atômico no campo. |
|
Observe que, como esses métodos ignoram validações, é possível salvar documentos inválidos no banco de dados e acabar com documentos inválidos no aplicativo (o que posteriormente não seria salvo por meio de uma chamada save
devido às validações com falha).
cluster de operação atômica
As operações atômicas podem ser agrupadas usando o método #atomically
em um documento. Todas as operações dentro do bloco fornecido ao #atomically
são enviadas para o cluster em um único comando atômico. Por exemplo:
person.atomically do person.inc(age: 1) person.set(name: 'Jake') end
#atomically
os blocos podem estar aninhados. O comportamento padrão é gravar as alterações realizadas por cada bloco assim que o bloco terminar:
person.atomically do person.atomically do person.inc(age: 1) person.set(name: 'Jake') end raise 'An exception' # name and age changes are still persisted end
Este comportamento pode ser alterado ao especificar a opção join_context: true
como #atomically
, ou globalmente ao definir aopção de configuração join_contexts
como true
. Quando a união de contexto está habilitada, os blocos #atomically
aninhados são unidos aos blocos externos, e somente o bloco mais externo (ou o primeiro bloco em que join_contexts
é falso) grava as alterações no cluster. Por exemplo:
person.atomically do person.atomically(join_context: true) do person.inc(age: 1) person.set(name: 'Jake') end raise 'An exception' # name and age changes are not persisted end
O comportamento de ligação de contexto pode ser habilitado globalmente por padrão, definindo a opção join_context
na configuração Mongoid. Neste caso, especificar join_context: false
em um bloco #atomically
pode ser utilizado para obter o comportamento de contexto de persistência independente.
Se uma exceção for gerada em um bloco #atomically
que ainda não persistiu suas alterações no cluster, quaisquer alterações de atributo pendentes em modelos Mongoid serão revertidas. Por exemplo:
person = Person.new(name: 'Tom') begin person.atomically do person.inc(age: 1) person.set(name: 'Jake') person.name # => 'Jake' raise 'An exception' end rescue Exception person.name # => 'Tom' end
As operações atômicas descritas nesta seção aplicam-se a um documento de cada vez; portanto, o aninhamento de blocos #atomically
invocados em vários documentos não faz com que as alterações nos diferentes documentos sejam persistidas atomicamente juntas. Entretanto, o MongoDB oferece transações multidocumento a partir da versão 4.0 do servidor, proporcionando persistência atômica em diversos documentos.
Recarregando
Use o método reload
para buscar a versão mais recente de um documento do banco de dados. Quaisquer modificações não salvas nos atributos do documento serão perdidas:
band = Band.create!(name: 'foo') # => #<Band _id: 6206d06de1b8324561f179c9, name: "foo", description: nil, likes: nil> band.name = 'bar' band # => #<Band _id: 6206d06de1b8324561f179c9, name: "bar", description: nil, likes: nil> band.reload # => #<Band _id: 6206d06de1b8324561f179c9, name: "foo", description: nil, likes: nil>
Quando um documento é recarregado, todas as suas associações incorporadas também são recarregadas na mesma query (já que os documentos incorporados são armazenados no documento pai do servidor). Se um documento tiver associações referenciadas, as associações carregadas não serão recarregadas, mas seus valores serão limpos, de modo que essas associações sejam carregadas do banco de dados no próximo acesso.
Observação
Algumas operações em associações, por exemplo, tarefas, persistem no novo documento. Nesses casos, pode não haver nenhuma modificação não salva para reverter por meio do recarregamento. No exemplo a seguir, a atribuição da array vazia à associação é imediatamente mantida e o recarregamento não faz nenhuma alteração no documento:
# Assuming band has many tours, which could be referenced: band = Band.create!(tours: [Tour.create!]) # ... or embedded: band = Band.create!(tours: [Tour.new]) # This writes the empty tour list into the database. band.tours = [] # There are no unsaved modifications in band at this point to be reverted. band.reload # Returns the empty array since this is what is in the database. band.tours # => []
Se o modelo tiver uma chave de shard definida, o valor da chave de shard será incluído na query de recarga.
Se o banco de dados não contiver um documento correspondente, o Mongoid normalmente levanta Mongoid::Errors::DocumentNotFound
. No entanto, se a opção de configuração raise_not_found_error
estiver definida como false
e o banco de dados não contiver um documento correspondente, o Mongoid substituirá o documento atual por um documento recém-criado cujos atributos são definidos como valores padrão. É importante ressaltar que isso geralmente faz com que o _id
do documento seja alterado, como demonstra o exemplo a seguir:
band = Band.create! # => #<Band _id: 6206d00de1b8324561f179c7, name: "foo", description: nil, likes: nil> Mongoid.raise_not_found_error = false band.destroy band.reload # => #<Band _id: 6206d031e1b8324561f179c8, name: nil, description: nil, likes: nil>
Por esta razão, não é recomendado utilizar reload
quando raise_not_found_error
está configurado para false
.
A recarregar documentos não guardados
reload
pode ser chamado quando o documento ainda não tiver sido persistente. Nesse caso, reload
executa uma query find
usando o valor id
especificado no documento (e o valor da chave de shard, se houver uma chave de shard definida):
existing = Band.create!(name: 'Photek') # Unsaved document band = Band.new(id: existing.id) band.reload band.name # => "Photek"
Acessando valores de campo
Mongoid fornece várias maneiras de acessar valores de campo.
Observação
Getters e Setters
A maneira recomendada é usar os métodos de getter e setter gerados para cada campo declarado:
class Person include Mongoid::Document field :first_name end person = Person.new person.first_name = "Artem" person.first_name # => "Artem"
Para usar esse mecanismo, cada campo deve ser declarado explicitamente, ou a classe do modelo deve permitir campos dinâmicos.
Getters e setters personalizados
É possível definir explicitamente os métodos getter e setter para fornecer um comportamento personalizado ao ler ou gravar campos, por exemplo, transformações de valores ou armazenamento de valores com nomes de campos diferentes. Neste caso, os métodos read_attribute
e write_attribute
podem ser utilizados para ler e escrever os valores diretamente no hash de atributos:
class Person include Mongoid::Document def first_name read_attribute(:fn) end def first_name=(value) write_attribute(:fn, value) end end person = Person.new person.first_name = "Artem" person.first_name # => "Artem" person.attributes # => {"_id"=>BSON::ObjectId('606477dc2c97a628cf47075b'), "fn"=>"Artem"}
Observação
Os setters personalizados são chamados durante a atribuição de atributos aninhados, no entanto, eles são chamados antes que as associações sejam configuradas. Devido a isso, as associações nem sempre podem estar disponíveis durante esses métodos, e é encorajado a incluir verificações de sua presença sempre que se referir a eles. Os retornos de chamada também podem ser usados para executar operações em determinados eventos, e as associações já terão sido configuradas e estarão disponíveis durante sua execução.
read_attribute
& write_attribute
Os métodos read_attribute
e write_attribute
também podem ser utilizados explicitamente. Note que, se um campo especificar o nome do campo de armazenamento, read_attribute
e write_attribute
aceitarão o nome do campo declarado ou o nome do campo de armazenamento para as operações:
class Person include Mongoid::Document field :first_name, as: :fn field :last_name, as: :ln end person = Person.new(first_name: "Artem") # => #<Person _id: 60647a522c97a6292c195b4b, first_name(fn): "Artem", last_name(ln): nil> person.read_attribute(:first_name) # => "Artem" person.read_attribute(:fn) # => "Artem" person.write_attribute(:last_name, "Pushkin") person # => #<Person _id: 60647a522c97a6292c195b4b, first_name(fn): "Artem", last_name(ln): "Pushkin"> person.write_attribute(:ln, "Medvedev") person # => #<Person _id: 60647a522c97a6292c195b4b, first_name(fn): "Artem", last_name(ln): "Medvedev">
read_attribute
e write_attribute
não exigem que um campo com o nome usado seja definido, mas escrever valores de campo com write_attribute
também não faz com que o respectivo campo seja definido:
person.write_attribute(:undefined, "Hello") person # => #<Person _id: 60647b212c97a6292c195b4c, first_name(fn): "Artem", last_name(ln): "Medvedev"> person.attributes # => {"_id"=>BSON::ObjectId('60647b212c97a6292c195b4c'), "first_name"=>"Artem", "last_name"=>"Medvedev", "undefined"=>"Hello"} person.read_attribute(:undefined) # => "Hello" person.undefined # raises NoMethodError
Quando read_attribute
é utilizado para acessar um campo ausente, ele retorna nil
.
Acesso ao hash
As instâncias de modelo do Mongoid definem os métodos []
e []=
para oferecer acesso de estilo do Hash
aos atributos. []
é um nome alternativo para read_attribute
e []=
é um nome alternativo para write_attribute
; consulte a seção sobre read_attribute e write_attribute para obter a descrição detalhada de seu comportamento.
class Person include Mongoid::Document field :first_name, as: :fn field :last_name, as: :ln end person = Person.new(first_name: "Artem") person["fn"] # => "Artem" person[:first_name] # => "Artem" person[:ln] = "Medvedev" person # => #<Person _id: 606483742c97a629bdde5cfc, first_name(fn): "Artem", last_name(ln): "Medvedev"> person["last_name"] = "Pushkin" person # => #<Person _id: 606483742c97a629bdde5cfc, first_name(fn): "Artem", last_name(ln): "Pushkin">
Gravações de atributos em massa
Nos casos em que você deseja definir vários valores de campo de uma só vez, há algumas maneiras diferentes de fazer isso também.
# Get the field values as a hash. person.attributes # Set the field values in the document. 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", )
rastreamento sujo
O Mongoid suporta o rastreamento de campos alterados ou "sujos" com uma API que espelha a do Active Model. Se um campo definido tiver sido modificado em um modelo, o modelo será marcado como sujo e algum comportamento adicional entrará em jogo.
Exibindo alterações
Existem várias maneiras de ver o que foi alterado em um modelo. As alterações são registradas desde o momento em que um documento é instanciado, seja como um novo documento ou por meio do carregamento do banco de dados até o momento em que ele é salvo. Qualquer operação de persistência limpa as alterações.
class Person include Mongoid::Document field :name, type: String end person = Person.first person.name = "Alan Garner" # Check to see if the document has changed. person.changed? # true # Get an array of the names of the changed fields. person.changed # [ :name ] # Get a hash of the old and changed values for each field. person.changes # { "name" => [ "Alan Parsons", "Alan Garner" ] } # Check if a specific field has changed. person.name_changed? # true # Get the changes for a specific field. person.name_change # [ "Alan Parsons", "Alan Garner" ] # Get the previous value for a field. person.name_was # "Alan Parsons"
Observação
Definir as associações em um documento não faz com que os hashes changes
ou changed_attributes
sejam modificados. Isto é verdade para todas as associações, sejam elas referenciadas ou incorporadas. Note que alterar o campo _id(s) em associações referenciadas faz com que as alterações apareçam nos hashes changes
e changed_attributes
.
Redefinindo alterações
Você pode redefinir as alterações de um campo para seu valor anterior ligando para o método de redefinição.
person = Person.first person.name = "Alan Garner" # Reset the changed name back to the original person.reset_name! person.name # "Alan Parsons"
Persistência
A Mongoid usa o rastreamento sujo como o núcleo de suas operações de persistência. Ele analisa as alterações em um documento e atualiza atomicamente apenas o que foi alterado, ao contrário de outras estruturas que gravam o documento inteiro em cada salvamento. Se nenhuma alteração tiver sido feita, o Mongoid não atingirá o banco de dados em uma chamada para Model#save
.
Visualizando alterações anteriores
Depois que um documento persistir, você pode ver quais foram as alterações anteriores ligando para Model#previous_changes
.
person = Person.first person.name = "Alan Garner" person.save # Clears out current changes. # View the previous changes. person.previous_changes # { "name" => [ "Alan Parsons", "Alan Garner" ] }
Atualizando campos de contêiner
Esteja ciente de que, até MONGOID-2951 for resolvido, todos os campos, incluindo os do contêiner, devem ser atribuídos para que seus valores permaneçam no banco de banco de dados.
Por exemplo, adicionar a um conjunto como este não funciona:
class Band include Mongoid::Document field :tours, type: Set end band = Band.new band.tours # => #<Set: {}> band.tours << 'London' # => #<Set: {"London"}> band.tours # => #<Set: {}>
Em vez disso, o valor do campo deve ser modificado fora do modelo e atribuído de volta ao modelo da seguinte forma:
class Band include Mongoid::Document field :tours, type: Set end band = Band.new tours = band.tours # => #<Set: {}> tours << 'London' # => #<Set: {"London"}> band.tours = tours # => #<Set: {"London"}> band.tours # => #<Set: {"London"}>
Documentos somente leitura
Os documentos podem ser marcados como somente leitura de duas maneiras, dependendo do valor do sinalizador de feição Mongoid.legacy_readonly
:
Se esse sinalizador estiver desativado, um documento será marcado como somente leitura quando o método #readonly!
for chamado nesse documento. Um documento somente leitura, com este sinalizador desativado, criará um erro ReadonlyDocument ao tentar executar qualquer operação de persistência, incluindo (mas não limitado a) salvar, atualizar, excluir e destruir. Observe que o carregamento não redefine o estado somente leitura.
band = Band.first band.readonly? # => false band.readonly! band.readonly? # => true band.name = "The Rolling Stones" band.save # => raises ReadonlyDocument error band.reload.readonly? # => true
Se esse sinalizador estiver ativado, um documento será marcado como somente leitura quando esse documento tiver sido projetado (ou seja, usando #only
ou #without
). Um documento somente leitura, com esse sinalizador ativado, não poderá ser excluído ou destruído (um erro ReadonlyDocument
será gerado), mas poderá ser salvo e atualizado. O status somente leitura é redefinido ao recarregar o documento.
class Band include Mongoid::Document field :name, type: String field :genre, type: String end band = Band.only(:name).first band.readonly? # => true band.destroy # => raises ReadonlyDocument error band.reload.readonly? # => false
Substituição readonly?
Outra maneira de tornar um documento somente leitura é substituindo o somente leitura? :
class Band include Mongoid::Document field :name, type: String field :genre, type: String def readonly? true end end band = Band.first band.readonly? # => true band.destroy # => raises ReadonlyDocument error