Runtime changing model with mongodb/mongoid

前端 未结 3 1755
太阳男子
太阳男子 2021-02-03 12:08

I\'ve to add several fields in a mongoid model, I know there is not migration with MongoDB but if I go on without dropping the DB, making rails to \"regenerate\" the DB entirely

相关标签:
3条回答
  • 2021-02-03 12:40

    In general it should be possible to update old documents with the new fields at runtime. There is no need for migrations in MongoDB.

    You maybe want to write rake tasks to update your old documents with the new fields and default values.

    You could find out these documents by checking those new fields which have per default a nil value.


    Update

    Easy style:

    If you define a new field with a default value, this value should always be used as long as you set a new one:

    app/models/my_model.rb

    class MyModel
      include Mongoid::Document
      field :name, type: String
      field :data, type: String
      # NEW FIELD
      field :note, type: String, default: "no note given so far!"
    end
    

    If you query your database you should get your default value for documents which haven't this field before your extension:

    (rails console)

    MyModel.first
    #=> #<MyModel …other fields…, note: "no note given so far!">
    

    I tested this with a fresh rails stack with a current mongoid on Ruby 1.9.2 - should work with other stacks, too.

    More complicated/complex style:

    If you didn't set a default value, you'll get nil for this new field.

    app/models/my_model.rb

    class MyModel
      include Mongoid::Document
      field :name, type: String
      field :data, type: String
      # NEW FIELD
      field :note, type: String
    end
    

    (rails console)

    MyModel.first
    #=> #<MyModel …other fields…, note: nil>
    

    Then you could set up a rake task and migration file like in this example:

    lib/tasks/my_model_migration.rake:

    namespace :mymodel do
      desc "MyModel migration task"
      task :migrate => :environment do
        require "./db/migrate.rb"
      end
    end
    

    db/migrate.rb:

    olds = MyModel.where(note: nil)
    # Enumerator of documents without a valid :note field (= nil)
    olds.each do |doc|
      doc.note = "(migration) no note given yet"
      # or whatever your desired default value should be
      doc.save! rescue puts "Could not modify doc #{doc.id}/#{doc.name}"
      # the rescue is only a failsafe statement if something goes wrong
    end
    

    Run this migration with rake mymodel:migrate.

    This is only a starting point and you can extend this to a full mongoid migration engine.

    The task :migrate => :environment do … is necessary, otherwise rake won't load models.

    0 讨论(0)
  • 2021-02-03 12:48

    It is a little ridiculous to say that you don't need migrations with mongodb or mongoid. Any sophisticated app needs to be refactored from time to time and that can mean pulling fields out of disparate documents into a new one.

    Writing one off rake tasks is way less convenient and error prone than having migrations be part of your deploy script so that it always gets run on every environment.

    https://github.com/adacosta/mongoid_rails_migrations brings AR style migrations to mongoid.

    You might need them less often, but you will certainly need them as an app grows.

    0 讨论(0)
  • 2021-02-03 12:49

    Below is a nice code example for data migration script with mongoid and the ruby mongo driver - to be used when your updated model no longer match production data.

    http://pivotallabs.com/users/lee/blog/articles/1548-mongoid-migrations-using-the-mongo-driver

    I whish we would stop using "no migrations with mongoid" as slogan. It'll turn people to MongoDB for the wrong reasons, and it's only partially true. No schema, true, but data still needs to be maintained, which IMO is harder with MongoDB than RDBMs. There are other, great reasons for choosing MongoDB and it depends on your problem.

    0 讨论(0)
提交回复
热议问题