-
-
Save rishiip/27ed24b71ce1ea1ed47b575778c516de to your computer and use it in GitHub Desktop.
counter cache extension for mongoid orm
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Mongoid | |
module CounterCache | |
extend ActiveSupport::Concern | |
module ClassMethods | |
# Use Case: | |
# | |
# keep a cached count of embedded collections in the parent collection(s) | |
# | |
# for example, if a Post embeds many Comments, and there have been 2 | |
# comments embedded in the the first post, we can do the following: | |
# | |
# >> Post.first.comments_count # 2 | |
# | |
# which just queries for the post's attribute. | |
# | |
# The parent counter field should follow the format: | |
# | |
# pluralized embedded collection name + "_count" | |
# | |
# Again, using our example from above, Post would have a field of | |
# "comments_count" (type Integer, default of 0). If no | |
# configuration is provided to the counter_cache class method, this | |
# format will be derivated and assumed. | |
# | |
# All parents of the embedded document will be checked for a counter | |
# cache to incremement or decrement. | |
# | |
# Usage: | |
# | |
# class Playlist | |
# include Mongoid::Document | |
# include Mongoid::Timestamps | |
# embeds_many :tracks | |
# field :comments_count, type: Integer, default: 0 | |
# end | |
# | |
# class Track | |
# include Mongoid::Document | |
# include Mongoid::Timestamps | |
# embedded_in :posts | |
# embeds_many :comments, cascade_callbacks: true | |
# | |
# field :comments_count, type: Integer, default: 0 | |
# end | |
# | |
# class Comment | |
# include Mongoid::Document | |
# include Mongoid::Timestamps | |
# include Mongoid::CounterCache # where all the magic happens! | |
# embedded_in :tracks | |
# counter_cache # (optional) :field => "some_field_count", must match parent(s) field definition(s) | |
# end | |
# | |
# Then ... | |
# >> # some setup is assumed | |
# >> p = Playlist.first # comments_count = 0 | |
# >> t = p.tracks.first # comments_count = 0 | |
# >> t.comments << Comment.new | |
# >> p.save # true | |
# >> t.comments_count # 1 | |
# >> p.comments_count # 1 | |
def counter_cache(options = {}) | |
counter_field = (options[:field] || "#{self.name.downcase.pluralize}_count").to_s | |
after_create do |document| | |
current_document = document | |
while current_document.embedded? | |
parent = current_document._parent | |
parent.inc(counter_field, 1) if parent.respond_to? counter_field | |
current_document = current_document._parent | |
end | |
end | |
after_destroy do |document| | |
current_document = document | |
while current_document.embedded? | |
parent = current_document._parent | |
parent.inc(counter_field, -1) if parent.respond_to? counter_field | |
current_document = current_document._parent | |
end | |
end | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment