2013-04-09 4 views
9

Nếu một trong những người đầu tiên xây dựng mô hình của họ với một liên kết thuộc tính và has_many và sau đó nhận ra họ cần phải di chuyển đến một embedded_in và embeds_many hiệp hội, làm thế nào sẽ làm điều này mà không làm mất hiệu lực hàng ngàn hồ sơ? Cần di chuyển chúng bằng cách nào đó.Làm thế nào để di chuyển từ thuộc_to, sang embedded_in trong Mongoid?

Trả lời

4

Tôi không chắc chắn giải pháp của mình là đúng hay không. Đây là một cái gì đó bạn có thể cố gắng để thực hiện nó.

Giả sử Bạn có các mô hình - như thế này

#User Model 
class User 
    include Mongoid::Document 
    has_many :books 
end 

#Book Model 
class Book 
    include Mongoid::Document 
    field :title 
    belongs_to :user 
end 

Tại bước đầu tiên tôi sẽ tạo ra một mô hình tương tự như mô hình Book trên nhưng nó nhúng thay vì tham chiếu.

#EmbedBook Model 
class EmbedBook 
    include Mongoid::Document 
    field :title 
    embedded_in :user 
end 

#User Model (Update with EmbedBook Model) 
class User 
    include Mongoid::Document 
    embeds_many :embed_books 
    has_many :books 
end 

Sau đó tạo một Mongoid Migration với một cái gì đó như thế này cho ví dụ

class ReferenceToEmbed < Mongoid::Migration 
    def up 
    User.all.each do |user| 
     user.books.each do |book| 
     embed_book = user.embed_books.new 
     embed_book.title = book.title 
     embed_book.save 
     book.destroy 
     end 
    end 
    end 
    def down 
    # I am not so sure How to reverse this migration so I am skipping it here 
    end 
end 

trên Sau khi chạy di cư. Từ đây, bạn có thể thấy sách tham chiếu được nhúng nhưng tên của mô hình được nhúng là EmbedBook và Model Book vẫn còn ở đó

Do đó, bước tiếp theo là làm sách mẫu thành dạng nhúng.

class Book 
    include Mongoid::Document 
    embedded_in :user 
    field :title 
end 

class User 
    include Mongoid::Document 
    embeds_many :books 
    embeds_many :embed_books 
end 

Vì vậy, tiếp theo sẽ là di chuyển loại embedbook để đặt loại

class EmbedBookToBook < Mongoid::Migration 
    def up 
    User.all.each do |user| 
     user.embed_books.each do |embed_book| 
     book = user.books.new 
     book.title = embed_book.title 
     book.save 
     embed_book.destroy 
    end 
    end 
    def down 
    # I am skipping this portion. Since I am not so sure how to migrate back. 
    end 
end 

Bây giờ Nếu bạn thấy sách được thay đổi từ tham chiếu đến nhúng. Bạn có thể xóa mô hình EmbedBook để thực hiện thay đổi hoàn tất.

  • Đây chỉ là gợi ý. Hãy thử điều này trên sự phát triển của bạn trước khi thử sản xuất. Vì, tôi nghĩ có thể có điều gì đó sai trong đề xuất của tôi.
+0

Cảm ơn, tôi đã đề xuất của bạn và tạo ra một số nhiệm vụ cào để di chuyển. – Dean

1

10gen có một vài bài viết về mô hình dữ liệu mà có thể là hữu ích:

Hãy nhớ rằng có hai hạn chế trong MongoDB khi nói đến nhúng:

  • tài liệu kích thước giới hạn là 16MB - điều này ngụ ý một số tối đa của tài liệu nhúng, ngay cả khi bạn chỉ cần nhúng đối tượng id của họ
  • nếu bạn muốn tìm kiếm trên tất cả các tài liệu được nhúng từ cấp cao nhất, sau đó không nhúng, nhưng sử dụng tài liệu được tham chiếu thay thế!
1

Hãy thử những bước sau:

  1. Trong User mô hình rời mối quan hệ has_many :books, và thêm mối quan hệ nhúng với một cái tên khác để không ghi đè lên các phương pháp books .

    class User 
         include Mongoid::Document 
    
         has_many :books 
         embeds_many :embedded_books, :class_name => "Book" 
        end 
    

    Bây giờ nếu bạn gọi phương thức embedded_books từ một User dụ mongoid nên trả lại một mảng trống.

  2. Nếu không có thêm bất kỳ mối quan hệ nhúng để Book mô hình, viết kịch bản riêng chuyển đổi của bạn:

    class Book 
        include Mongoid::Document 
    
        field :title, type: String 
        field :price, type: Integer 
        belongs_to :user 
    
        def self.migrate 
         attributes_to_migrate = ["title","price"] # Use strings not symbols, 
                   # we keep only what we need. 
                   # We skip :user_id field because 
                   # is a field related to belongs_to association. 
         Book.all.each do |book| 
         attrs = book.attributes.slice(*attributes_to_migrate) 
         user = book.user // through belong_to association 
         user.embedded_book.create!(attrs) 
         end 
        end 
    end 
    

    Calling Book.migrate bạn nên có tất cả các Sách sao chép bên trong mỗi người dùng là ai gắn liền với mối quan hệ belongs_to.

  3. Bây giờ, bạn có thể xóa mối quan hệ has_manybelongs_to và cuối cùng, chuyển sang làm sạch giải pháp nhúng.

    class User 
        include Mongoid::Document 
    
        embeds_many :books 
    end 
    
    class Book 
        include Mongoid::Document 
    
        field :title, type: String 
        field :price, type: Integer 
        embedded_in :user 
    end 
    

tôi đã không kiểm tra giải pháp này, nhưng về mặt lý thuyết nên làm việc, cho tôi biết.

0

Tôi có một câu trả lời ngắn gọn ngắn hơn nhiều:

Giả sử rằng bạn có mô hình tương tự:

#User Model 
class User 
    include Mongoid::Document 
    has_many :books 
end 

#Book Model 
class Book 
    include Mongoid::Document 
    field :title 
    belongs_to :user 
end 

Vì vậy, thay đổi nó để nhúng:

#User Model 
class User 
    include Mongoid::Document 
    embeds_many :books 
end 

#Book Model 
class Book 
    include Mongoid::Document 
    field :title 
    embedded_in :user 
end 

Và tạo ra một sự chuyển đổi mongoid như thế này:

class EmbedBooks < Mongoid::Migration 
    @@attributes_to_migrate = [:title] 
    def self.up 
    Book.unscoped.where(:user_id.ne => nil).all.each do |book| 
     user = User.find book[:user_id] 
     if user 
     attrs = book.attributes.slice(*@@attributes_to_migrate) 
     user.books.create! attrs 
     end 
    end 
    end 

    def self.down 
    User.unscoped.all.each do |user| 
     user.books.each do |book| 
     attrs = @@attributes_to_migrate.reduce({}) do |sym,attr| 
      sym[attr] = book[attr] 
      sym 
     end 
     attrs[:user] = user 

     Book.find_or_create_by(**attrs) 
     end 
    end 
    end 
end 

Điều này làm việc vì khi bạn truy vấn từ cấp lớp, nó đang tìm kiếm bộ sưu tập cấp cao nhất (vẫn tồn tại ngay cả khi bạn thay đổi quan hệ của bạn), và book[:user_id] là một mẹo để truy cập thuộc tính tài liệu thay vì các phương thức tự tạo cũng tồn tại vì bạn chưa làm gì để xóa chúng.

Vì vậy, ở đó bạn có nó, một di chuyển đơn giản từ quan hệ đến nhúng