Visão geral
Associações no Mongoid permitem criar relacionamentos entre modelos. Neste guia, você pode aprender a usar associações incorporadas para armazenar diferentes tipos de documentos na mesma coleção. O Mongoid suporta associações incorporadas com as seguintes macros:
embeds_oneembeds_manyembedded_inrecursively_embeds_onerecursively_embeds_many
As seções a seguir descrevem como usar esses tipos de associação.
Incorpora um
Para especificar que um modelo de classe contém um documento incorporado de um tipo de classe diferente, use a macro embeds_one na classe principal e a macro embedded_in na classe incorporada. O exemplo a seguir cria uma classe Band com uma classe Label incorporada :
class Band include Mongoid::Document embeds_one :label end class Label include Mongoid::Document field :name, type: String embedded_in :band end
O Mongoid armazena documentos incorporados com a macro embeds_one no documento principal como um campo com o mesmo nome da classe incorporada. Os documentos Label anteriores são armazenados no documento Band, conforme mostrado no exemplo a seguir:
# Band document { "_id" : ObjectId("..."), "label" : { "_id" : ObjectId("..."), "name" : "Periphery", } }
Você pode armazenar o documento incorporado com um nome diferente usando a opção store_as, conforme mostrado no exemplo a seguir:
class Band include Mongoid::Document embeds_one :label, store_as: "record_label" end
Incorpora muitos
Para especificar que um modelo de classe contém vários documentos incorporados de um tipo de classe diferente, use a macro embeds_many na classe principal e a macro embedded_in na classe incorporada. O exemplo a seguir cria uma classe Band com vários documentos do tipo Album incorporados:
class Band include Mongoid::Document embeds_many :albums end class Album include Mongoid::Document field :name, type: String embedded_in :band end
O Mongoid armazena documentos incorporados com a macro embeds_many no documento principal como um campo de array com o mesmo nome da classe incorporada. Os documentos Album anteriores são armazenados no documento Band, conforme mostrado no exemplo a seguir:
{ "_id" : ObjectId("..."), "albums" : [ { "_id" : ObjectId("..."), "name" : "Omega", } ] }
Você pode armazenar o documento incorporado com um nome diferente usando a opção store_as, conforme mostrado no exemplo a seguir:
class Band include Mongoid::Document embeds_many :albums, store_as: "records" end
Incorporação recursiva
Você pode incorporar um ou mais documentos do mesmo tipo em uma classe principal usando as macros recursively_embeds_one e recursively_embeds_many. Ambas as macros fornecem acessadores para os documentos pai e filho por meio de um método parent_* e um método child_*, em que * representa o nome da classe. O exemplo a seguir cria uma classe Band que incorpora recursivamente vários outros documentos Band para representar vários nomes de bandas:
class Band include Mongoid::Document field :name, type: String recursively_embeds_many end
Você pode acessar os documentos principal e secundário por meio dos métodos parent_band e child_band, conforme mostrado no exemplo a seguir:
root = Band.new(name: "Linkin Park") # Add child bands child_one = root.child_band.build(name: "Lincoln Park") child_two = root.child_band.build(name: "Xero") # Access parent band child_one.parent_band # Outputs: root
Associações incorporadas à consulta
Você pode acessar documentos incorporados ao consultar a collection da classe principal usando a notação de ponto.
O exemplo a seguir usa notação de ponto para consultar documentos do tipo Tour que estão incorporados em uma classe Band . A query retorna documentos com um valor tours.year de 2000 ou superior:
Band.where('tours.year' => {'$gte' => 2000})
Você pode usar o método de projeção pluck para recuperar documentos incorporados sem recuperar seus documentos pai associados, conforme mostrado no exemplo a seguir:
# Get awards for bands that have toured since 2000 Band.where('tours.year' => {'$gte' => 2000}).pluck(:awards)
Você pode usar os métodos de query do Mongoid para realizar a correspondência incorporada, o que permite consultar associações incorporadas de documentos que já estão carregados no aplicação. O Mongoid implementa a correspondência incorporada sem enviar queries para o servidor.
Os seguintes operadores de query são compatíveis com correspondência incorporada:
O exemplo a seguir consulta o campo tours incorporado de um documento Band carregado usando o operador de comparação $gte:
band = Band.where(name: 'Astral Projection').first tours = band.tours.where(year: {'$gte' => 2000})
A correspondência incorporada em documentos carregados tem as seguintes limitações conhecidas:
A correspondência incorporada não está implementada para as seguintes funcionalidades:
Operadores que executam código JavaScript, como $where
Operadores implementados por meio de outras funcionalidades do servidor , como $expr e $jsonSchema
O Mongoid expande os argumentos
Rangepara hashes com condições$gtee$lte. Isso pode levar a queries inválidas em alguns casos e gera uma exceçãoInvalidQuery.Com o operador
$regex, você não pode especificar um objeto de expressão regular como um padrão e, ao mesmo tempo, fornecer opções para o campo$options. Você só pode fornecer opções se o padrão de expressão regular for uma string.
Omitir campos _id
Por padrão, o Mongoid adiciona um campo _id aos documentos incorporados. Você pode omitir esse campo de documentos incorporados especificando explicitamente o campo _id em seu modelo e omitindo o valor padrão. O exemplo a seguir instrui o Mongoid a não adicionar um campo _id à classe Albums :
class Album include Mongoid::Document field :name, type: String field :_id, type: Object embedded_in :band end
Na classe Albums anterior, o campo _id não é adicionado automaticamente. Sem um valor padrão, o Mongoid não armazena o valor no banco de dados, a menos que você forneça um em seu modelo.
Excluir associações incorporadas
Você pode excluir documentos filhos de associações embeds_many usando um dos seguintes métodos:
cleardelete_alldestroy_all
O clear método utiliza o operador operador $unset para remover uma associação incorporada inteira do documento principal. O método clear não executa nenhuma chamada de resposta destroy. O exemplo a seguir usa o método clear para remover todas as associações incorporadas da classe Band :
band = Band.find(...) band.tours.clear
O delete_all método utiliza o operador operador $pullAll para remover documentos em uma associação incorporada. delete_all carrega a associação se ela ainda não tiver sido carregada e remove apenas os documentos existentes no aplicação. O método delete_all não executa nenhuma chamada de resposta destroy. O exemplo a seguir usa o método delete_all para remover todos os documentos Album incorporados da classe Band:
band = Band.find(...) band.tours.delete_all
O destroy_all método também usa o operador $pullAll para remover documentos em uma associação incorporada. Ele também executa quaisquer chamada de resposta destroy definidas nos documentos associados. O exemplo a seguir usa o método destroy_all para remover todos os documentos Album incorporados da classe Band :
band = Band.find(...) band.tours.destroy_all