2012-01-09 6 views
6

Bạn sẽ làm cách nào để sao chép sâu tài liệu trong MongoDB (mongoid)Tài liệu bản sao sâu với các liên kết được nhúng

Tôi đã thử một cái gì đó như thế này;

original = Car.find(old_id) 
@car = original.clone 
@car._id = BSON::ObjectId.new 

Nhưng tôi gặp sự cố deserialization các giá trị sau đó.

Làm cách nào để tạo bản sao sâu với tất cả các thuộc tính của tài liệu ngoại trừ _id?

Chỉnh sửa: Sau khi làm theo ví dụ của Zachary, tôi gặp một số vấn đề với lớp tuần tự hóa tùy chỉnh cho các tài liệu được sao chép.

class OptionHash 
    include Mongoid::Fields::Serializable 

    # Convert the keys from Strings to Symbols 
    def deserialize(object) 
    object.symbolize_keys! 
    end 

    # Convert values into Booleans 
    def serialize(object) 
    object.each do |key, value| 
    object[key] = Boolean::MAPPINGS[value] 
    end 
end 

Đối tượng không có tài liệu trùng lặp. Car.find (old_id). Các thuộc tính thực sự không bao gồm trường với serialization tùy chỉnh, tại sao lại như vậy và làm thế nào tôi có thể đưa nó vào?

+0

bạn có thể cụ thể hơn về các vấn đề không? – Barrie

+0

Bạn có vấn đề gì sau này? –

+0

Tôi đoán vấn đề là id của tài liệu được nhúng không được cập nhật. tức là xung đột với id của tài liệu được nhúng trong tài liệu gốc. – Yeggeps

Trả lời

7

Bạn không cần phải gọi .clone về điều này, bạn có thể sử dụng dữ liệu thô từ attributes. Ví dụ: phương thức/ví dụ dưới đây sẽ cung cấp các id mới trong toàn bộ tài liệu nếu nó tìm thấy một.

def reset_ids(attributes) 
    attributes.each do |key, value| 
     if key == "_id" and value.is_a?(BSON::ObjectId) 
      attributes[key] = BSON::ObjectId.new 
     elsif value.is_a?(Hash) or value.is_a?(Array) 
      attributes[key] = reset_ids(value) 
     end   
    end 
    attributes 
end 


original = Car.find(old_id) 
car_copy = Car.new(reset_ids(original.attributes)) 

Và bây giờ bạn có bản sao Ô tô. Điều này là không hiệu quả mặc dù vì nó phải đi qua toàn bộ băm cho bản ghi để tìm ra nếu có bất kỳ tài liệu nhúng trong một tài liệu nhúng. Bạn nên tự mình thiết lập lại cấu trúc nếu bạn biết nó sẽ như thế nào, ví dụ, nếu bạn có một phần được nhúng vào ô tô, thì bạn chỉ có thể làm:

original = Car.find(old_id) 
car_copy = Car.new(original.attributes) 
car_copy._id = BSON::ObjectId.new 
car_copy.parts.each {|p| p._id = BSON::ObjectId.new} 

Hiệu quả hơn rất nhiều chỉ cần thiết lập lại chung.

+0

Xin cảm ơn, đã cập nhật câu hỏi vì tôi đã gặp một số vấn đề với cách tiếp cận này. – Yeggeps

+0

Hrm. Tôi không có nhiều kinh nghiệm với Mongoid :: Fields :: Serializable. Tôi sẽ kiểm tra xem loại dữ liệu nào đang được chuyển khi bạn gọi 'original.attributes'. Bạn có nhận được dữ liệu được tuần tự hóa hoặc dữ liệu được deserialized không? Nó có thể là một vấn đề với nó đi qua các dữ liệu deserialized vì vậy bạn cần phải serialize nó trước khi nhân bản. –

+0

Bài đăng tuyệt vời .. Tôi chỉ phải tính đến bảo mật mass_assignment trong đường ray3 để thực hiện công việc này. Bằng cách loại bỏ attr_accessible khỏi mô hình nó hoạt động như một nét duyên dáng .. Cảm ơn! – Tigraine

0

Bạn phải sử dụng Car.instantiate nếu bạn đã bản địa hoá các lĩnh vực để mã là

def reset_ids(attributes) 
    attributes.each do |key, value| 
     if key == "_id" && value.is_a?(Moped::BSON::ObjectId) 
      attributes[key] = Moped::BSON::ObjectId.new 
     elsif value.is_a?(Hash) || value.is_a?(Array) 
      attributes[key] = reset_ids(value) 
     end   
    end 
    attributes 
end 

car_original = Car.find(id) 
car_copy = Car.instantiate(reset_ids(car_original.attributes)) 
car_copy.insert 

Giải pháp này không phải là rất sạch nhưng tôi không nhận thấy tốt hơn.