TLTR: 結果が重複することはありません。
map 関数が何かを発行するとき、reduce 関数が何かを返すとき、それはカップル [キー、値] です。コレクションに格納すると、エントリごとに、出力は次のような Mongoid ドキュメントとして表されます。
{
"_id" => "my key",
"value" => "my value"
}
その点を明確にしたいと思います。キーはとして保存される_id
ため、コレクション内で一意です。
Map/Reduce 出力オプションを参照して、MongoDb が既存のコレクションに出力するときに重複キーを処理する方法を確認してください。
replace (デフォルト) :既存のコレクションのコンテンツが削除され、出力がそこに入ります
merge :既存のコレクションが保持されます。同じキー (_id) を持つ結果が存在する場合、それは新たにマップ/削減されたものに置き換えられます。
reduce :既存のコレクションが保持されます。同じキー (_id) を持つ結果が存在する場合、MongoDB はそれを取得し、新しくマップ/縮小されたものを取得し、それらの 2 つに対して reduce 関数を実行し、結果を保存します。
したがって、結果が重複することはありません。
編集:
ここで、「output reduce を適用する方法と、コレクションの結果を呼び出す方法を教えてもらえますか」(応答が非常に長いため) に応答します。
多くの方法があります。とりわけ例を見てみましょう:
class Post
include Mongoid::Document
include Mongoid::Timestamps
field :tags, :type => Array
end
Post.create(:tags => ["Dog", "Cat"])
Post.create(:tags => ["Dog", "Puppy"])
これをマップ/削減しましょう:
map = %Q{
function() {
this.tags.forEach(function(tag){
emit(tag, { count: 1 });
});
}
}
reduce = %Q{
function(key, values) {
var result = { count: 0 };
values.forEach(function(value) {
result.count += value.count;
});
return result;
}
}
Post.map_reduce(map, reduce).out(replace: "tags")
わかりました、結果を「tags」という名前のコレクションに入れ、それを上書きします。
それにアクセスするためのモデルを作成できます。
class Tag
include Mongoid::Document
field :value, :type => Hash
end
dog = Tag.find("Dog")
dog._id # => "Dog"
dog.value["count"] # => 2
楽しみのために、最後に map/reduce を行ったときのタイムスタンプを保持しているとしましょう。あなたreduce
はそれを段階的に行うことができます:
Post.where(:created_at.gt => Time.at(my_timestamp)).map_reduce(map, reduce).out(reduce: "tags")
** 編集: 固定マップ機能 **