0

In a Rails app I have a collection of events with a list of invitees for each of them. I would like to have the whole list of invitees as a single flatten list. A simple .map is not an option as there are thousands of events with as much of invitees...

class Event
  include Mongoid::Document
  include Mongoid::Timestamps
  has_many :invitees
end

I was trying to use Map/Reduce for that with the following code:

map = %Q{
  function() { 
    var event = this;
    this.invitees.forEach(function(invitee){
      emit(invitee.id, { event: event.title, id: invitee.id });
    }); 
  }
}


reduce = %Q{
  function(key, values) {
    var result = [];
    values.forEach(function(v) {
      result.push(v)
    });
    return { value: result };
  }
}

Event.map_reduce(map, reduce).out(replace: "invitees")

But Mongo returns the following error: Mongo::Error::OperationFailure (TypeError: this.invitees is undefined :)

Is Map/Reduce the right way to achieve this operation ? If so, what am I doing wrong ?

1 Answers1

0

These days map/reduce is deprecated and instead using the aggregation pipeline is recommended.

To perform the equivalent of joins in MongoDB, use $unwind aggregation pipeline stage: https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/

You could then use $project to reduce the size of the result set to the fields/subdocuments that you care about: https://docs.mongodb.com/manual/reference/operator/aggregation/project/

Mongoid does not provide aggregation pipeline helpers, thus you have to go through the driver to use it. Driver documentation: https://docs.mongodb.com/ruby-driver/current/tutorials/ruby-driver-aggregation/

To get a collection object in a Rails app using Mongoid:

ModelClass.collection
D. SM
  • 13,584
  • 3
  • 12
  • 21