MongoDB Mongoid 下按时间分类取数据的问题

arthur_h · 2013年11月14日 · 最后由 Arthur_h 回复于 2013年11月15日 · 2269 次阅读

新手求抱大腿^_^

最近在用mongoid,在写一个model的时候发现有地方需要用类似于group_by的命令,但是找了一圈貌似没有对应的包装方法,小伙伴们有类似的方法经验能指教下嘛?。。

情况:比如有一组新闻数据年份不等,需要按照年份分别归类拿出。

自己的笨办法:翻了半天mongodb文档发现map_reduce可以满足我的需求写出类似与group_by命令后在拿数据出来。

想到的问题: 1.map_reduce据说效率不高而且这样加上后面的查询貌似一次取数据2次hit数据库(map_reduce,where) 2.map_reduce中基本为mongodb的js command所完成所以增加了后面的人的维护难度(比较喜欢ruby的语法)

写的随手了点纯文字流了。。感觉满常见的需求应该有高效解决办法,小伙伴们回答下感激感激~~~~~~~

共收到 6 条回复

Model.between(created_at: [t_start, t_end]) ?

#1楼 @dddd1919 事先不知道t_start, t_end。。。所以要类似group_by一下?

#2楼 @Arthur_h group_by把日期按range分组也是要自己写范围,不过要是分组统计的话 mongoid也提供 group_by的啊

建议参考map_reduce或者mongodb的aggregate map_reduce一般用来做一些复杂的数据模型,如果简单的话aggregate framework就可以解决。 你所说的两次访问db的性能暂时不考虑,以后可以用其他方法来解决,担心数据库性能不如担心rails性能。

如果你想写成ruby style的code的话,可以做一些module,例如下面以前抽象出来的module,直接集成在model上,api 就像这样

Model.aggregate_by_date(:field => FIELD, :from =>FROM, :to =>TO, :duration => year | month | day)
def aggregate_by_date *args, &block
        options = args.extract_options!
        duration = options[:duration]

        self.aggregate do
          match do |m|
            if options[:field] && (options[:from] || options[:to])
              m[options[:field]] = {}
              m[options[:field]]["$gte"] = options[:from] if options[:from]
              m[options[:field]]["$lt"] = options[:to] if options[:to]
            end
          end

          group do |g|
            g['count'] = {"$sum" => 1}
          end

          group_id do |id|
            id.year = {"$year" => "$created_at"} if duration.include?("year")
            id.month = {"$month" => "$created_at"} if duration.include?("month")
            id.day = {"$dayOfMonth" => "$created_at"} if duration.include?("day")
          end

          yield(self)

          sort do |s|
            s._id = 1
          end
        end
      end

#5楼 @hxplove01 谢谢,aggregate这个方案非常好完全满足了需求(看了和mapreduce的性能对比),惭愧自己看文档的时候没注意到aggregate。。。数据库两次查询的话aggregate一次后把group的结果丢到redis里面算了,反正不会是已经变动的。再次感谢!

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册