Runtime Changing Model with Mongodb/Mongoid

Runtime changing model with mongodb/mongoid

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.

Rails/Mongoid database migrations

Write a custom rake task to migrate the data as needed

Extracting, modelling and changing data model, with mongoid/mongodb

You do two things:

  • Filter the users with db query instead of filtering in application
  • only fetch fields you need from db, rather than the whole user objects(assuming you have some other stuff in user, which you omitted here for brevity)

    Competitor = Struct.new(:html_url, :description, :user)
    competitors = []
    User.where('watchlists.tags_array' => %w[ruby web framework]).
    only(:nickname, :watchlists).each do |u|
    u.watchlists.where(:tags_array => %w[ruby web framework]).each do |wl|
    competitors << Competitor.new(wl.html_url, wl.description, u.nickname)
    end
    end

PS: Probably you do not want to use map on User.all, it will require a lot of memory if you have lots of heavy user documents. Also, you are not using the mapped users, but instead collecting results in the competitors array yourself, so each should work just fine.

rails mongoid dynamc model fails

Final solution:

Create all classes dynamically. While dynamically creating/instatiating classes I gave them a new name (Prefix+name of the model) so they do not override my initial class defintions which I need to seed the db (or for some internal processes). There is quite some database overhead with this: Reading the meta data for all classes including the associations and also dynamically create classes for all associated models or inheritances. So I only dynamically create a class and constantize it whenever the model changes (manipulating fields or associations/inheritance). For all other cases I use the existing class if already constantized.

How to update a boolean value with mongoid and rails?

I got it to work. I had to pass the job ID from the preview page to the controller again.

<%= form_for @job, url: '/jobs/publish/'+@job.id do |f| %>

And then revised the controller to:

def update
job = Job.find(params[:id])
job.publish = true
job.save!
redirect_to '/jobs'
end

And change the route to "patch":

patch '/jobs/publish/:id' => 'jobs#update'

Renaming field in Mongoid does not update field in class

When you run #rename, you interact with MongoDB. The change of document structure is stored in the database. This method does not interact with ruby source code, you need to edit it by yourself.

Btw. I can't recall any ruby/rails method (besides ones in rake tasks and generators) that interacts with the source code stored in files.



Related Topics



Leave a reply



Submit