2012-05-30 2 views
0

필드 채우기를 통해 모든 문서를 수정하려는 커다란 컬렉션이 있습니다.MongoDB map/reduce를 사용하여 데이터를 이전 할 수 있습니까?

class Post 
    field :comment_count, type: Integer 
    has_many :comments 
end 
class Comment 
    belongs_to :post 
end 

내가 좋아하는 뭔가 직렬 실행할 수 있습니다 :

간단한 예는 각 게시물에 댓글 수를 캐싱 될 수

Post.all.each do |p| 
    p.udpate_attribute :comment_count, p.comments.count 
end 

그러나 24 시간 실행 복용 (대형 수집). 나는 mongo의 map/reduce가 이것을 위해 사용될 수 있는지 궁금해하고 있었다? 그러나 저는 아직 큰 모범을 보지 못했습니다.

주석 컬렉션을 매핑하고 축소 된 결과를 posts 컬렉션에 저장한다고 생각합니다. 나는 올바른 길을 가고 있는가?

답변

0

MongoDB map/reduce를 사용하여 데이터 이전을 "도울"수 있습니다. 불행하게도 완전히 서버 측 마이그레이션을 수행하는 데 사용할 수 없습니다. ---> {_id : post_id를, 값 : {COMMENT_COUNT : (post_id를, {1 COMMENT_COUNT을}) 방출

  1. 지도 각 주석 : 당신이 올바른 궤도에, 기본적인 생각은하는 것 1 }}
  2. 값 줄이기 {comment_count : N} N은 총계입니다. ---> {_id : post_id, 값 : {comment_count : N}}
  3. 출력 옵션 {reduce : 'posts'}을 map/reduce comment_counts의 결과를 게시물 컬렉션으로 되돌립니다.

다소 광범위한 조사가 끝나면 가까이에, 하지만 서버 측 마이그레이션을 완전히 차단하는 문제가 있습니다. 결과의 모양은 {_id : KEY, value : MAP_REDUCE_VALUE}입니다. 우리는 지금이 모양을 고수하고 있습니다. 주변을 둘러 볼 방법이없는 것 같습니다. 따라서이 모양 외부의 전체 원본 문서를 줄이기위한 입력 (이 모양 바깥의 데이터가 누락 됨), 이나 축소 된 결과로이 도형 외부의 문서를 업데이트 할 수 없습니다. 따라서 게시물 모음에 대한 "최종"업데이트는 클라이언트를 통해 프로그래밍 방식으로 수행해야합니다. 이 수정은 좋은 수정 요청 일 것 같습니다.

다음은 Ruby에서 MongoDB map/reduce를 사용하여 모든 comment_count를 계산하는 방법을 보여주는 작업 예제입니다. 그런 다음 프로그래밍 방식으로 map_reduce_results 컬렉션을 사용하여 posts 컬렉션의 comment_count를 업데이트합니다. reduce 함수는 사용 시도에서 제외되었습니다. {reduce : 'posts'}

약간의 실험을 통해 답변을 확인할 수 있습니다. 또는 완전히 작동하지 않는 서버 측 시도를 게시 할 수 있습니다. 원하는 경우 고정 모델로 완성하십시오. Ruby에서 MongoDB map/reduce를 이해하는 데 도움이되기를 바랍니다. (검사 JSON 루비의 혼합 미안)

시험/유닛/comment_test.rb

require 'test_helper' 

class CommentTest < ActiveSupport::TestCase 
    def setup 
    @map_reduce_results_name = 'map_reduce_results' 
    delete_all 
    end 

    def delete_all 
    Post.delete_all 
    Comment.delete_all 
    Mongoid.database.drop_collection(@map_reduce_results_name) 
    end 

    def dump(title = nil) 
    yield 
    puts title 
    Post.all.to_a.each do |post| 
     puts "#{post.to_json} #{post.comments.collect(&:text).to_json}" 
    end 
    end 

    def generate 
    (2+rand(2)).times do |p| 
     post = Post.create(text: 'post_' + p.to_s) 
     comments = (2+rand(3)).times.collect do |c| 
     Comment.create(text: "post_#{p} comment_#{c}") 
     end 
     post.comments = comments 
    end 
    end 

    def generate_and_migrate(title = nil) 
    dump(title + ' generate:') { generate } 
    dump(title + ' migrate:') { yield } 
    end 

    test "map reduce migration" do 
    generate_and_migrate('programmatic') do 
     Post.all.each do |p| 
     p.update_attribute :comment_count, p.comments.count 
     end 
    end 
    delete_all 
    generate_and_migrate('map/reduce') do 
     map = "function() { emit(this.post_id, {comment_count: 1}); }" 
     reduce = <<-EOF 
     function(key, values) { 
      var result = {comment_count: 0}; 
      values.forEach(function(value) { result.comment_count += value.comment_count; }); 
      return result; 
     } 
     EOF 
     out = @map_reduce_results_name #{reduce: 'posts'} 
     result_coll = Comment.collection.map_reduce(map, reduce, out: out) 
     puts "#{@map_reduce_results_name}:" 
     result_coll.find.each do |doc| 
     p doc 
     Post.find(doc['_id']).update_attribute :comment_count, doc['value']['comment_count'].to_i 
     end 
    end 
    end 
end 

테스트 출력

Run options: --name=test_map_reduce_migration 

# Running tests: 

programmatic generate: 
{"_id":"4fcae3bde4d30b21e2000001","comment_count":null,"text":"post_0"} ["post_0 comment_0","post_0 comment_1","post_0 comment_2"] 
{"_id":"4fcae3bde4d30b21e2000005","comment_count":null,"text":"post_1"} ["post_1 comment_1","post_1 comment_0","post_1 comment_2","post_1 comment_3"] 
{"_id":"4fcae3bde4d30b21e200000a","comment_count":null,"text":"post_2"} ["post_2 comment_1","post_2 comment_3","post_2 comment_0","post_2 comment_2"] 
programmatic migrate: 
{"_id":"4fcae3bde4d30b21e2000001","comment_count":3,"text":"post_0"} ["post_0 comment_0","post_0 comment_1","post_0 comment_2"] 
{"_id":"4fcae3bde4d30b21e2000005","comment_count":4,"text":"post_1"} ["post_1 comment_1","post_1 comment_0","post_1 comment_2","post_1 comment_3"] 
{"_id":"4fcae3bde4d30b21e200000a","comment_count":4,"text":"post_2"} ["post_2 comment_1","post_2 comment_3","post_2 comment_0","post_2 comment_2"] 
map/reduce generate: 
{"_id":"4fcae3bee4d30b21e200000f","comment_count":null,"text":"post_0"} ["post_0 comment_0","post_0 comment_1"] 
{"_id":"4fcae3bee4d30b21e2000012","comment_count":null,"text":"post_1"} ["post_1 comment_2","post_1 comment_0","post_1 comment_1"] 
{"_id":"4fcae3bee4d30b21e2000016","comment_count":null,"text":"post_2"} ["post_2 comment_0","post_2 comment_1","post_2 comment_2","post_2 comment_3"] 
map_reduce_results: 
{"_id"=>BSON::ObjectId('4fcae3bee4d30b21e200000f'), "value"=>{"comment_count"=>2.0}} 
{"_id"=>BSON::ObjectId('4fcae3bee4d30b21e2000012'), "value"=>{"comment_count"=>3.0}} 
{"_id"=>BSON::ObjectId('4fcae3bee4d30b21e2000016'), "value"=>{"comment_count"=>4.0}} 
map/reduce migrate: 
{"_id":"4fcae3bee4d30b21e200000f","comment_count":2,"text":"post_0"} ["post_0 comment_0","post_0 comment_1"] 
{"_id":"4fcae3bee4d30b21e2000012","comment_count":3,"text":"post_1"} ["post_1 comment_2","post_1 comment_0","post_1 comment_1"] 
{"_id":"4fcae3bee4d30b21e2000016","comment_count":4,"text":"post_2"} ["post_2 comment_0","post_2 comment_1","post_2 comment_2","post_2 comment_3"] 
. 

Finished tests in 0.072870s, 13.7231 tests/s, 0.0000 assertions/s. 

1 tests, 0 assertions, 0 failures, 0 errors, 0 skips 
관련 문제