How can I use Mongoid and ActiveRecord in parallel

2020-05-19 07:30发布

I'm using rails 3, and began my application with ActiveRecord. Now, I have many models, and the relations are starting to get complicated, and some could be more simply expressed with a Document-Oriented structure, so I'd like to try migrating to MongoDB and use Mongoid.

I've always heard that you didn't have to eitheer use all MongoDB or nothing, but that you could use the two in parallel while migrating. I don't see how to go about this from the docs though.

For example, I have:

class User < ActiveRecord::Base
   has_many :items
   has_many :products, :through => :items
end

class Product < ActiveRecord::Base
   has_many :items
end

class Item < ActiveRecord::Base
   belongs_to :user
   belongs_to :product

   # alot of data that fits a hierarchical document-oriented structure
end

I'd like to ideally begin by replacing my Item activerecord model with a Mongoid document, so my items are stored in MongoDB, and my Users and Products can stay in my SQL DB

Thing is, I don't see how to do this. Am I going about this the right way?

Perhaps another alternative is to keep a base AR Item

class Item < ActiveRecord::Base
   has_one :mongodb_item  ?? # I know this is wrong
end

class MongodbItem
   include Mongoid::Document
   belongs_to AR_Item ???    # I know this is also wrong
end

Thanks!

4条回答
淡お忘
2楼-- · 2020-05-19 08:05

What I did was just mock the relationship with methods in each the AR model and the Mongoid model like so.

# visit_session.rb
class VisitSession
  include Mongoid::Document
  include Mongoid::Timestamps

  field :user_id, type: Integer
  index({user_id: 1},{name: :user_id_index})

  # Mock a belongs_to relationship with User model
  def user
    User.find(self.user_id)
  end
end

# user.rb
class User < ActiveRecord::Base

  # Mock a has_many relationship with VisitSession Mongoid model
  def visit_sessions
    VisitSession.where(user_id: self.id)
  end
end

Of course you won't have all the AR methods on VisitSession Mongoid model but you'll at least be able to mock the relationship between the two fairly well.

Hope this helps.

查看更多
迷人小祖宗
3楼-- · 2020-05-19 08:13

I don't see any reason why you couldn't have both ActiveRecord and Mongoid models in the same application. That being said, I'm almost certain that you'll run into issues if you try to create relationships between your ActiveRecord and Mongoid models.

If your ActiveRecord models are heavily inter-related, but better suited to a document structure, then I would suggest just biting the bullet and converting them all to Mongoid documents. I had to do this recently on a (large-ish) project, and it's significantly less stressful than you would think.

If you have good unit tests for your models, then it should be a total snap. If you don't - write your unit tests first, make sure they pass with ActiveRecord and then start migrating things over to Mongoid.

查看更多
Viruses.
4楼-- · 2020-05-19 08:24

... just for tracking purpose, I'd like to add something I just found out on this field:

DRY up your SQL+NoSQL Rails projects

查看更多
Root(大扎)
5楼-- · 2020-05-19 08:29

i created a module for spoofing the relation in active record models.

module MongoRelations
  def belongs_to_mongo(name, options = {})
    id_name = "mongo_#{name}_id".to_sym
    mongo_model = options[:through] || "Mongo::#{name.to_s.camelize}".constantize

    define_method(name) do
      id = send(id_name)
      mongo_model.find(id) if id.present?
    end

    define_method("#{name}=") do |value|
      send("#{id_name}=".to_sym, value.try(:id).to_s)
    end
  end
end

In my SQL table, I name my mongo relations using the convention mongo_XXX_id, instead of XXX_id

I also namespace all my mongo models under Mongo::

in my active record model

class Foo < ActiveRecord::Base
    belongs_to_mongo :XXX
end

which allows

Foo.new.XXX = Mongo.find('123')
Foo.XXX

or

Foo.new.XXX_id = '123'
Foo.XXX
查看更多
登录 后发表回答