No commit activity in last 3 years
No release in over 3 years
Mongoid MapReduce provides simple aggregation features for your Mongoid models
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

>= 0
~> 0.4.3
~> 0.9.2
~> 2.6

Runtime

~> 1.3
~> 2.0
 Project Readme

Mongoid MapReduce

Mongoid MapReduce provides simple aggregation functions to your models using MongoDB map/reduce.

travis

How simple is simple?

Short answer: very!

There are two map/reduce formulae:

Aggregates: Provide a map key and a list of fields to be aggregated via addition.

Array List: Provide an array field, the values will be individually aggregated via addition.

Getting Started

First, add mongoid-mapreduce to your Gemfile:

gem 'mongoid-mapreduce'

Next, include the module in any models for collections you'll be wanting to map/reduce on:

class Employee
  include Mongoid::Document
  include Mongoid::MapReduce

  field :name
  field :division
  field :awards, :type => Integer
  field :age, :type => Integer
  field :male, :type => Integer
  field :rooms, :type => Array
end

You can now use the map_reduce method on your model to aggregate data using your choice of aggregation formula.

# Create a few example employees
Employee.create :name => 'Alan', :division => 'Software', :age => 20, :awards => 5, :male => 1, :rooms => [1,2,3]
Employee.create :name => 'Bob', :division => 'Software', :age => 25, :awards => 4, :male => 1, :rooms => [1,2,3]
Employee.create :name => 'Chris', :division => 'Hardware', :age => 30, :awards => 3, :male => 1, :rooms => [4,5,6]
Employee.create :name => 'Darcy', :division => 'Sales', :age => 35, :awards => 3, :male => 0, :rooms => [1,2,3,4,5,6]

# Aggregate formula (the default): produces 3 records, one for each division.
divs = Employee.map_reduce(:division, :fields => [:age, :awards])
divs.length               # => 3
divs.find('Software').age # => 45
divs['Hardware'].awards   # => 3
divs.first.awards         # => 9
divs.last.age             # => 35
divs.keys                 # => ['Hardware', 'Software', 'Sales']
divs.has_key?('Sales')    # => true
divs.to_hash              # => { "Software" => ..., "Hardware" => ..., "Sales" => ... }

# Array Value formula: produces 6 records, one for each room. Does not take any fields.
rooms = Employee.map_reduce(:rooms, :formula => :array_values)
rooms.length          # => 6
rooms.find(1)._count  # => 3
rooms.counts["5"]     # => 2
rooms.counts          # => { "1" => 3, "2" => 3, "3" => 3, "4" => 2, "5" => 2, "6" => 2 }

You can also add Mongoid criteria before the operation:

# Produces 2 records, one for each matching division (men only!)
divs = Employee.where(:male => 1).map_reduce(:division, :fields => [:age, :awards])
divs.length               # => 2
divs.has_key?('Sales')    # => false

You choose to supply fields as arguments or in a block:

# These are the same:
Employee.where(:age.gt => 20).map_reduce(:division, :fields => [:age, :awards])
Employee.where(:age.gt => 20).map_reduce(:division) do
  field :age
  field :awards
end

Fields can be of any type supported by Mongoid serialization, and field type is specified in block configuration:

divs = Employee.map_reduce(:division) do
  field :age, :type => Integer
  field :awards, :type => Float
end

divs.find('Software').age     # => 60
divs.find('Software').awards  # => 9.0

Additional meta fields are included in the results:

NOTE: _key_name and _key_value are discarded when converting to Hash.

# Produces 2 records, one for each matching division (men only!)
divs = Employee.map_reduce(:division, :fields => [:age, :awards])
divs.find('Software')._key_name   # => :division
divs.find('Software')._key_value  # => "Software"
divs.find('Software').division    # => "Software" (_key_name => _key_value)
divs.find('Software')._count      # => 2

# You can choose another name for the count field
Employee.map_reduce(:division, :count_field => :num).find('Software').num  #=> 2

Enhancements and Pull Requests

If you find the project useful but it doesn't meet all of your needs, feel free to fork it and send a pull request.

License

MIT license, go wild.