Miguel Ping
Miguel Ping

Reputation: 18347

Mongoid: convert embedded document into referenced/own collection

I need to convert an embedded document onto its own collection, so it can be referenced from another collection.

Lets suppose I have a Parent that embeds many Childs. I was thinking of something along this:

Parent.all.each do |p|
 p.childs.all.each do |c|
  c.raw_attributes['parent_id'] = p.id
 end
 p.save! #will save parent and cascade persist all childs onto their own coll
end

Is this an option? Ideally I would run this in a console and I would only change mongoid mappings from embed_* to has_*, so I wouldn't need to change the rest of my code or use another collection as staging.

Upvotes: 9

Views: 1252

Answers (4)

Chip Roberson
Chip Roberson

Reputation: 572

Here is an updated version of Sergio Tulentsev's approach with Pencilcheck's addition and an update of sbauch's correction.

First, leave the embeds_many/embedded_in statements in place in your models.

Second, run something like this block of code:

child_coll =  Mongoid.client(:default).database.collection(:children)
Parent.all.each do |p|
  p.childs.all.each do |c|
    dup = c.attributes
    dup['_id'] = nil
    dup['parent_id'] = p.id
    child_coll.insert_one dup # save children to separate collection
    c.destroy
  end
  p.childs = nil # remove embedded data
  p.save
end

Third, change your embeds_many to has_many and your embedded_in to belongs_to.

Fini.

Upvotes: 1

sbauch
sbauch

Reputation: 830

too little rep to comment, but I think Sergio's (otherwise very helpful) answer may be outdated. With mongoid 3.0.5 I couldn't use

child_coll = Mongoid.database.collection('children')

but instead used

child_coll = Mongoid.default_session[:children]

which did the trick for me

Upvotes: 7

Pencilcheck
Pencilcheck

Reputation: 2922

For me I need to remove the '_id' attribute before inserting otherwise I will get Duplicated key Error.

Upvotes: 1

Sergio Tulentsev
Sergio Tulentsev

Reputation: 230356

I think, the code should look more like this (didn't test)

child_coll = Mongoid.database.collection('children')

Parent.all.each do |p|
  p.childs.all.each do |c|
    c.attributes['parent_id'] = p.id

    child_coll.insert c.attributes # save children to separate collection
  end

  p.childs = nil # remove embedded data
  p.save
end

After that, you can change your embeds_many to has_many and (hopefully) it should work well.

Upvotes: 10

Related Questions