如果首先使用belongs_to和has_many关联构建模型,然后意识到他们需要转移到embedded_in和embeds_many关联,那么如何在不使数千条记录失效的情况下执行此操作?需要以某种方式迁移它们。
答案 0 :(得分:4)
我不太确定我的解决方案是否正确。这是你可能试图完成的事情。
假设您有模型 - 像这样
#User Model
class User
include Mongoid::Document
has_many :books
end
#Book Model
class Book
include Mongoid::Document
field :title
belongs_to :user
end
在第一步,我将创建另一个类似于上面的Book模型的模型,但它是嵌入的而不是引用的。
#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
然后为上面的例子创建一个类似于此的Mongoid Migration
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
运行迁移后。从这里您可以看到嵌入式参考书籍,但嵌入式模型的名称是EmbedBook,模型Book仍在那里
所以下一步就是将模型书改为嵌入式。
class Book
include Mongoid::Document
embedded_in :user
field :title
end
class User
include Mongoid::Document
embeds_many :books
embeds_many :embed_books
end
所以下一步是将embedbook类型迁移到图书类型
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
现在如果您看到Book已从引用更改为嵌入式。 您可以删除EmbedBook模型以完成更改。
答案 1 :(得分:1)
10gen有几篇关于数据建模的文章可能很有用:
请记住,在嵌入时,MongoDB有两个限制:
答案 2 :(得分:1)
尝试以下步骤:
在User
模型中保留has_many :books
关系,然后添加。{
具有不同名称的嵌入式关系不会覆盖books
方法
class User
include Mongoid::Document
has_many :books
embeds_many :embedded_books, :class_name => "Book"
end
现在,如果您从embedded_books
实例调用User
方法
mongoid应该返回一个空数组。
在不向Book
模型添加任何嵌入关系的情况下,编写自己的关系
迁移脚本:
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
调用Book.migrate
您应该在每个用户中复制所有图书
与belongs_to关系相关联。
现在您可以删除has_many
和belongs_to
关系了
最后切换到清洁嵌入式解决方案。
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
我没有测试过这个解决方案,但理论上应该可行,请告诉我。
答案 3 :(得分:0)
我的答案简短得多:
我们假设你有相同的模型:
#User Model
class User
include Mongoid::Document
has_many :books
end
#Book Model
class Book
include Mongoid::Document
field :title
belongs_to :user
end
所以改成嵌入:
#User Model
class User
include Mongoid::Document
embeds_many :books
end
#Book Model
class Book
include Mongoid::Document
field :title
embedded_in :user
end
并生成像这样的mongoid迁移:
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
这是有效的,因为当您从类级别进行查询时,它正在查找顶级集合(即使您更改了关系,它仍然存在),book[:user_id]
是访问文档属性的技巧,而不是自动生成的方法也存在,因为你没有做任何删除它们。
所以你有它,从关系到嵌入式的简单迁移