1
votes

I'm trying to perform the following aggregation with Mongoid:

 Award.collection.aggregate( [ {"$project" => {:"value.amount"=> 1}} ] )

This returns:

#<Mongo::Collection::View::Aggregation:0x0055cc6e8658b8
@options={},
@pipeline=[{"$project"=>{:"value.amount"=>1}}],
@view=#<Mongo::Collection::View:0x47168257993960   
namespace='elvis_development.awards @selector={} @options={}>>

so no results but no errors either. This version has the same syntax as the example they give in the docs but I've tried different syntax too, with no success. In the mongo shell this:

db.awards.aggregate( [ { $project : { value.amount : 1 } } ] )

returns the desired results. I use MongoDB v3.0.7 and Mongoid 5.0.1 and this is my model:

class Award
  include Mongoid::Document
  include Mongoid::Elasticsearch

  # Associations
  belongs_to :document
  embeds_one :date, class_name: "AwardDate", inverse_of: :award
  embeds_one :value, class_name: "Value", inverse_of: :award

 accepts_nested_attributes_for :value, :date

  # Fields
 field :title, type: String
 field :description, type: String

 elasticsearch!({
  prefix_name: false,
  index_name: 'awards',
  wrapper: :load
 })
end 

Am I doing something wrong? I noticed in this example on mongo_ruby_driver Github that the $project aggregation is supported, but I've tried with both nested and not nested attributes with the same result. I realize I could do this with normal retrieval but I would prefer aggregations since they are faster and I have a large data set. Any thoughts would be very much appreciated.

1

1 Answers

3
votes

Modern releases of Mongoid (v5 and greater) now use a modern mongodb ruby driver rather than the older "moped" driver of Mongoid v3 and v4.

This means that .aggregate() returns a "cursor", or specifically a Mongo::Collection::View::Readable object instead of a plain array of objects, which is consistent with other modern driver releases.

So iterate the "cursor" instead, via the standard ways. i.e:

require "pp"

Award.collection.aggregate( [ {"$project" => { "value.amount"=> 1}} ] ).each do | doc |
    pp doc
end

Which will give you output like this for each document in the response:

{"_id"=>BSON::ObjectId('564c4836023fb886145f8063'), "value"=>{"amount"=>1.0}}

Just like you asked for.