今天在开发项目遇到一个问题,即一个模型要按其 embeded document 的 length 排序。
虽然最简单的就是加一个冗余字段 counter 之类的,但是还是先看看文档和 google 一把,最终还是没找到答案。
后来想想,ruby-china 源码应该有关于这方面的,哈哈,于是就想看看是怎么做的。
结果发现也是没有,但是却发现了 CounterCache 这个类,用于 cache 一些 counter。
代码也是十分简单。
module Mongoid
module CounterCache
extend ActiveSupport::Concern
module ClassMethods
def counter_cache(metadata)
counter_name = "#{metadata[:inverse_of]}_count"
set_callback(:create, :after) do |document|
relation = document.send(metadata[:name])
if relation
relation.inc(counter_name.to_sym => 1) if relation.class.fields.keys.include?(counter_name)
end
end
set_callback(:destroy, :after) do |document|
relation = document.send(metadata[:name])
if relation && relation.class.fields.keys.include?(counter_name)
relation.inc(counter_name.to_sym => -1)
end
end
end
end #ClassMethods
end #CounterCache
end #Mongoid
使用也十分简单,如在 reply 模型里(部分)
class Reply
include Mongoid::Document
include Mongoid::Timestamps
include Mongoid::BaseModel
include Mongoid::CounterCache
include Mongoid::SoftDelete
include Mongoid::MarkdownBody
include Mongoid::Mentionable
include Mongoid::Likeable
belongs_to :user, :inverse_of => :replies
belongs_to :topic, :inverse_of => :replies, touch: true
counter_cache :name => :user, :inverse_of => :replies
counter_cache :name => :topic, :inverse_of => :replies
end
这样的话,每 create 或者 destroy 一个 reply,则会自动更新 user 和 topic 模型里的 replies_count 这个字段。
哈哈,打算把这种思路引入到项目里来。