はい、DB でのメモ化は一般的なパターンです。MongoDB では、BSON の豊富な機能を利用して埋め込み配列を格納できるため、1 回の DB 要求で簡単かつ効率的にデータを取得できます。
MongoDB に埋め込まれたドキュメント配列には、いくつかのニュアンスがあります。次のテストは、配列の '$elemMatch' クエリ セレクターと '$' Update Array 演算子の使用法を示しています。また、クライアント側とサーバー側の両方の更新の例も含まれています。
http://docs.mongodb.org/manual/reference/operators/
毎月の更新は頻繁ではありませんが、事前に割り当てて、ドキュメントの増大によるオーバーヘッドを回避できます。事前割り当てには数行の追加コードが必要であり、年のエポックも処理する必要があります。
Ruby 1.9.3、モンゴイド 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
これが役立つことを願っています。