Pipeline de agregação
O Mongoid expõeo agregação pipeline do MongoDB, que é usado para construir fluxos de operações que processam e retornam resultados. O pipeline de agregação é um superconjunto da funcionalidade deestrutura de mapa/redução de obsoleta.
Uso básico
Consultando em várias coleções
O agregação pipeline pode ser usado para queries envolvendo várias associações referenciadas ao mesmo tempo:
class Band include Mongoid::Document has_many :tours has_many :awards field :name, type: String end class Tour include Mongoid::Document belongs_to :band field :year, type: Integer end class Award include Mongoid::Document belongs_to :band field :name, type: String end
Para recuperar bandas que fizeram turnês desde 2000 e têm pelo menos um prêmios, pode-se fazer o seguinte:
band_ids = Band.collection.aggregate([ { '$lookup' => { from: 'tours', localField: '_id', foreignField: 'band_id', as: 'tours', } }, { '$lookup' => { from: 'awards', localField: '_id', foreignField: 'band_id', as: 'awards', } }, { '$match' => { 'tours.year' => {'$gte' => 2000}, 'awards._id' => {'$exists' => true}, } }, {'$project' => {_id: 1}}, ]) bands = Band.find(band_ids.to_a)
Observe que o agregação pipeline, uma vez que é implementado pelo driver Ruby para MongoDB e não Mongoid, retorna objetos brutos BSON::Document
em vez de instâncias de modelo Mongoid::Document
. O exemplo acima projeta somente o campo _id
que é então utilizado para carregar modelos completos. Uma alternativa é não realizar tal projeção e trabalhar com campos brutos, o que eliminaria a necessidade de enviar a lista de IDs de documento para o Mongoid na segunda query (que pode ser grande).
Builder DSL
O Mongoid fornece suporte limitado para a construção do próprio pipeline de agregação usando um DSL de alto nível. Os seguintes operadores de pipeline de agregação são compatíveis:
Para construir um pipeline, chame os métodos de pipeline de agregação correspondentes em uma instância do Criteria
. As operações de pipeline de agregação são adicionadas ao pipeline
atributo da Criteria
instância . Para executar o pipeline, passe o pipeline
valor do atributo Collection#aggragegate
.
Por exemplo, dado os modelos a seguir:
class Tour include Mongoid::Document embeds_many :participants field :name, type: String field :states, type: Array end class Participant include Mongoid::Document embedded_in :tour field :name, type: String end
Podemos descobrir quais estados um participante visitou:
criteria = Tour.where('participants.name' => 'Serenity',). unwind(:states). group(_id: 'states', :states.add_to_set => '$states'). project(_id: 0, states: 1) pp criteria.pipeline # => [{"$match"=>{"participants.name"=>"Serenity"}}, # {"$unwind"=>"$states"}, # {"$group"=>{"_id"=>"states", "states"=>{"$addToSet"=>"$states"}}}, # {"$project"=>{"_id"=>0, "states"=>1}}] Tour.collection.aggregate(criteria.pipeline).to_a
grupo, grupo
O método group
adiciona um estágio de pipeline de agregação $group.
As expressões de campo suportam a sintaxe do operador de símbolo Mongoid :
criteria = Tour.all.group(_id: 'states', :states.add_to_set => '$states') criteria.pipeline # => [{"$group"=>{"_id"=>"states", "states"=>{"$addToSet"=>"$states"}}}]
Como alternativa, a sintaxe padrão do pipeline de agregação do MongoDB pode ser usada:
criteria = Tour.all.group(_id: 'states', states: {'$addToSet' => '$states'})
projeto, projeto
O método project
adiciona um estágio de pipeline de agregação do projeto $.
O argumento deve ser um Hash especificando a projeção:
criteria = Tour.all.project(_id: 0, states: 1) criteria.pipeline # => [{"$project"=>{"_id"=>0, "states"=>1}}]
Unwind
O método unwind
adiciona um estágio de pipeline de agregação $unwind.
O argumento pode ser um nome de campo , especificável como um símbolo ou uma string, ou um Hash ou uma instância BSON::Document
:
criteria = Tour.all.unwind(:states) criteria = Tour.all.unwind('states') criteria.pipeline # => [{"$unwind"=>"$states"}] criteria = Tour.all.unwind(path: '$states') criteria.pipeline # => [{"$unwind"=>{:path=>"$states"}}]