在Mongo文档中缓存/存储聚合的模式(Ruby、mongoid)?

在Mongo文档中缓存/存储聚合的模式(Ruby、mongoid)?,ruby,mongodb,design-patterns,mongoid,Ruby,Mongodb,Design Patterns,Mongoid,我正在收集一组账户中的推文,并希望进行计算,例如每个月(给定)的推文数,或给定月份内每个推文的平均推文长度 一旦该计算在过去一段时间内完成一次(例如,2010年5月,用户X推特每天4.2次),就不需要重新计算(大量删除过去的推特是一种边缘情况)……因此,在这种情况下,根据需要执行此聚合,然后在Mongo文档中记录它的基本模式是什么 例如: t = TwitterAccount.find_by(:screen_name=>'Bob') puts t.tweet_rate(:month=>

我正在收集一组账户中的推文,并希望进行计算,例如每个月(给定)的推文数,或给定月份内每个推文的平均推文长度

一旦该计算在过去一段时间内完成一次(例如,2010年5月,用户X推特每天4.2次),就不需要重新计算(大量删除过去的推特是一种边缘情况)……因此,在这种情况下,根据需要执行此聚合,然后在Mongo文档中记录它的基本模式是什么

例如:

t = TwitterAccount.find_by(:screen_name=>'Bob')
puts t.tweet_rate(:month=>5, :year=>2010)
# ...

puts t.tweet_rate(:month=>5, :year=>2010)
# cached/memoized result is stored inside document
我可以猜测如何编写自己的类来处理这个问题,但我认为这在NoSQL世界中是一种很常见的模式(我刚开始使用MongoDB),在NoSQL世界中,可以随意添加新属性


(我使用Ruby 1.9和Mongoid作为我的ORM,但从概念上讲这并不重要)

是的,在DB中进行记忆是一种常见的模式。使用MongoDB,您可以使用BSON的丰富功能来存储嵌入式阵列,这样您就可以通过一个DB请求轻松高效地获取数据

MongoDB中的嵌入式文档数组有一些细微差别。以下测试显示数组的“$elemMatch”查询选择器和“$”更新数组运算符的用法。它还提供了客户端和服务器端更新的示例

虽然每月更新的频率很低,但您可以预先分配,以避免文档增长带来的开销。预分配需要额外的几行代码,您还必须处理年份

Ruby 1.9.3、Mongoid 3.0.15、轻便摩托车1.3.1

class TwitterAccount
  include Mongoid::Document
  field :screen_name, type: String
  embeds_many :tweet_rates
end

class TweetRate
  include Mongoid::Document
  field :year, type: Integer
  field :month, type: Integer
  field :rate, type: Float
  embedded_in :twitter_account
end
测试/单元/tweet_rate_test.rb

require 'test_helper'

class TweetRateTest < ActiveSupport::TestCase

  def setup
    TwitterAccount.delete_all
    TwitterAccount.create(:screen_name => 'Bob')
  end

  test "monthly append" do
    t = TwitterAccount.find_by(:screen_name => 'Bob')
    assert_equal('Bob', t.screen_name)
    t.tweet_rates.create(:year => 2010, :month =>5, :rate => 12.3)
    t.save!
    tr = TwitterAccount.find_by(:screen_name => 'Bob').tweet_rates
    assert_equal(1, tr.size)
  end

  test "prealloc for a year" do
    t = TwitterAccount.find_by(:screen_name => 'Bob')
    assert_equal('Bob', t.screen_name)

    # prealloc for a whole year
    year = 2012
    (1..12).each do |month|
      t.tweet_rates.create(:year => year, :month => month, :rate => -1.0)
    end
    t.save!
    t = TwitterAccount.find_by(:screen_name => 'Bob')
    assert_equal(12, t.tweet_rates.size)

    # update a rate using client-side Ruby
    month, rate  = 10, 12.3
    t.tweet_rates.detect{|tr| tr.year == year && tr.month == month}.rate = rate
    t.save!
    assert_equal(rate, TwitterAccount.find_by(:screen_name => 'Bob')
                                     .tweet_rates.detect{|tr| tr.year == year && tr.month == month}.rate) # used #detect NOT overloaded #find

    # update a rate using MongoDB server-side
    month, rate = 11, 4.56
    TwitterAccount.where({ :screen_name => 'Bob',
                           :tweet_rates => { '$elemMatch' => { :year => year, :month => 11 } } })
                  .update('$set' => { 'tweet_rates.$.rate' => rate })
    assert_equal(rate, TwitterAccount.where({ :screen_name => 'Bob'}).first
                                     .tweet_rates.detect{|tr| tr.year == year && tr.month == month}.rate) # use #detect and NOT overloaded #find
  end
end
需要“测试助手”
类TweetRateTest“Bob”)
结束
测试“每月追加”吗
t=TwitterAccount.find_by(:screen_name=>“Bob”)
断言相等('Bob',t.screen_name)
t、 tweet_rates.create(:year=>2010,:month=>5,:rate=>12.3)
t、 救命!
tr=TwitterAccount.find_by(:screen_name=>Bob')。tweet_比率
断言_等于(1,tr.size)
结束
测试“预分配一年”do
t=TwitterAccount.find_by(:screen_name=>“Bob”)
断言相等('Bob',t.screen_name)
#预售一整年
年份=2012年
(1..12).每个月|
t、 创建(:year=>year,:month=>month,:rate=>-1.0)
结束
t、 救命!
t=TwitterAccount.find_by(:screen_name=>“Bob”)
断言相等(12,t.tweet\u rates.size)
#使用客户端Ruby更新速率
月份,费率=10,12.3
t、 tweet_rates.detect{tr | tr.year==year&&tr.month==month}.rate=rate
t、 救命!
assert_equal(rate,TwitterAccount.find_by(:screen_name=>'Bob'))
.tweet_rates.detect{tr.year==year&&tr.month==month}.rate)#已使用#检测未过载#查找
#使用MongoDB服务器端更新速率
月份,比率=11,4.56
TwitterAccount.where({:screen\u name=>“Bob”,
:tweet_rates=>{'$elemMatch'=>{:year=>year,:month=>11}})
.update('$set'=>{'tweet_rates.$.rate'=>rate})
assert_equal(rate,TwitterAccount.where({:screen_name=>'Bob'})。首先
.tweet_rates.detect{tr.year==year&&tr.month==month}.rate)#使用#检测并不重载#查找
结束
结束
希望这有帮助