No commit activity in last 3 years
No release in over 3 years
Makes one's life easier when working with events that have multiple occurrences, or a recurring schedule.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies
 Project Readme

Mongoid Occurrences

Build Status Gem Version Coverage Status

Facilitates aggregations for events with multiple occurrences or a recurring schedule.

Requirements

  • Mongoid 7+
  • MongoDB 3.4+

Installation

Add this line to your application's Gemfile:

gem 'mongoid_occurrences'

And then execute:

$ bundle

Or install it yourself as:

$ gem install mongoid_occurrences

Usage

Event

Define a Mongoid document that will embed occurrence definitions.

class Event
  include Mongoid::Document
  include MongoidOccurrences::HasOccurrences

  embeds_many_occurrences class_name: "Occurrence"
end

This document will gain the #assign_daily_occurrences! method (automatically triggered :after_validation), which expands all occurrence definitions in the embedded relation called #daily_occurrences.

The class will also gain the following scopes, useful for querying for events based on the #daily_occurrences:

  • .occurs_between(dtstart, dtend)
  • .occurs_from(dtstart)
  • .occurs_on(day)
  • .occurs_until(dtend)

Occurrence

Define a Mongoid document that defines the occurrence.

class Occurrence
  include Mongoid::Document
  include MongoidOccurrences::Occurrence

  embedded_in_event :event, class_name: 'Event'
end

This document will gain the #dtstart, #dtend and #all_day fields to define individual occurrences.

Recurring schedule is handled via the IceCube and MongoidIceCubeExtension gems. The model gains #schedule, and #schedule_dtstart, #schedule_dtend fields (with default values for schedule 1 year from now), along with #recurrence_rule= writer method.

It is possible to influence the way the occurrences are expanded into #daily_occurrences using the #operator enum field, which accepts the following values:

  • :append – appends to the list of #daily_occurrences (default)
  • :replace – replaces all occurrences that happen on the same day with itself
  • :remove - removes all occurrences that happen on the same day

Indexes

To optimize the performance of the above scope queries, you might want to add the following indexes:

index :'daily_occurrences.ds' => 1
index :'daily_occurrences.de' => 1

Aggregations

It is possible to aggregate (unwind) the events so that they are multiplied per daily occurrences. Example aggregations are included:

  • MongoidOccurrences::Aggregations::OccursBetween.instantiate(Event.criteria, dtstart, dtend)
  • MongoidOccurrences::Aggregations::OccursFrom.instantiate(Event.criteria, dtstart)
  • MongoidOccurrences::Aggregations::OccursOn.instantiate(Event.criteria, day)
  • MongoidOccurrences::Aggregations::OccursUntil.instantiate(Event.criteria, dtend)

The aggregations will add #_dtstart, #_dtend fields to the unwound documents. For easier access, mixin the MongoidOccurrences::HasFieldsFromAggregation to your Event class:

class Event
  include Mongoid::Document
  include MongoidOccurrences::HasFieldsFromAggregation
  include MongoidOccurrences::HasOccurrences

  embeds_many_occurrences class_name: "Occurrence"
end

This will automatically add #dtstart and #dtend fields with correct (demongoized) values, as well as the #all_day? method.

Embedded events

If your events are itself embedded:

class EventParent
  embeds_many :events, class_name: 'Event'
end

Simply add the following scopes on the parent document:

class EventParent
  scope :occurs_between, ->(dtstart, dtend) { elem_match(events: Event.occurs_between(dtstart, dtend).selector) }
  scope :occurs_from, ->(date_time) { elem_match(events: Event.occurs_from(date_time).selector) }
  scope :occurs_on, ->(date_time) { elem_match(events: Event.occurs_on(date_time).selector) }
  scope :occurs_until, ->(date_time) { elem_match(events: Event.occurs_until(date_time).selector) }

  include MongoidOccurrences::HasFieldsFromAggregation

  delegate :daily_occurrences, to: :event
end

You will then need to write your own aggregations with an extra step to $unwind the embedded #events, and your indexes will need to be adjusted as follows:

index :'events.daily_occurrences.ds' => 1
index :'events.daily_occurrences.de' => 1

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake test to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/tomasc/mongoid_occurrences.

License

The gem is available as open source under the terms of the MIT License.