Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to migrate from belongs_to, to embedded_in in Mongoid?

If one first build their models with a belong_to and has_many association and then realized they need to move to a embedded_in and embeds_many association, how would one do this without invalidating thousands of records? Need to migrate them somehow.

like image 207
Daniel Fischer Avatar asked Apr 09 '13 22:04

Daniel Fischer


2 Answers

I am not so sure my solution is right or not. This is something you might try to accomplish it.

Suppose You have models - like this

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

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

At first step I will create another model that is similar to the Book model above but it's embedded instead of referenced.

#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

Then create a Mongoid Migration with something like this for the above example

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

After running the migration. From here you can see that reference books are embedded, but the name for the embedded model is EmbedBook and model Book is still there

So the next step would be to make model book as embed instead.

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

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

So the next would be to migrate embedbook type to book type

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

Now If you see Book is changed from referenced to embedded. You can remove EmbedBook model to make the changing complete.

  • This is just the suggestion. Try this on your development before trying on production. Since, I think there might be something wrong in my suggestion.
like image 156
Suracheth Chawla Avatar answered Nov 19 '22 13:11

Suracheth Chawla


10gen has a couple of articles on data modeling which could be useful:

  • Data Modeling Considerations for MongoDB Applications

  • Embedded One-to-Many Relationships

  • Referenced One-to-Many Relationships

  • MongoDB Data Modeling and Rails

Remember that there are two limitations in MongoDB when it comes to embedding:

  • the document size-limit is 16MB - this implies a max number of embedded documents, even if you just embed their object-id
  • if you ever want to search across all embedded documents from the top-level, then don't embed, but use referenced documents instead!
like image 1
Tilo Avatar answered Nov 19 '22 12:11

Tilo