ruby-on-rails - 更改 Mongoid 中的字段类型而不丢失数据

标签 ruby-on-rails mongodb mongoid

如何运行迁移来更改 Mongoid/MongoDB 中的字段类型而不丢失任何数据?

就我而言,我正在尝试从 BigDecimal (存储为字符串)转换为 Integer 以存储一些钱。我需要将字符串十进制表示形式转换为整数的美分。我不想丢失现有数据。

我假设步骤可能类似于:

  1. 使用新名称创建新的整数字段,例如amount2
  2. 部署到生产环境并运行迁移(或 rake 任务),将每个 amount 转换为 amount2 的正确值
  3. (整个过程中现有代码仍在使用 amount,从用户的角度来看没有停机)
  4. 关闭网站进行维护,再次运行迁移以捕获在过去几分钟内可能发生更改的任何金额字段
  5. 删除amount并将amount2重命名为amount
  6. 部署新代码,要求amount为整数
  7. 恢复网站

看起来 Mongoid 提供了一个重命名方法:http://mongoid.org/docs/persistence/atomic.html#rename

但是我有点困惑这是如何使用的。如果您有一个名为 amount2 的字段(并且您已经删除了 amount),您只需运行 Transaction.rename :amount2, :amount ?然后我想这会立即破坏底层表示,因此您必须在此之后重新启动应用程序服务器?如果在 amount 仍然存在的情况下运行它会发生什么?它是否被覆盖、失败或尝试自行转换?

谢谢!

最佳答案

好吧,我成功了。我认为有一种更快的方法使用 mongo 控制台,如下所示: MongoDB: How to change the type of a field?

但我无法进行转换,因此在 Rails 控制台中选择了这种较慢的方法,并且停机时间更长。如果有人有更快的解决方案,请发布。

  • 使用新名称创建新的整数字段,例如amount2
  • 在控制台或 rake 任务中将每个amount 转换为amount2 的正确值

Mongoid.identity_map_enabled = false
Transaction.all.each_with_index do |t,i|
  puts i if i%1000==0
  t.amount2 = t.amount.to_money
  break if !t.save
end

请注意,由于 mongodb 游标,.all.each 工作正常(您不需要像 mysql 的常规 activerecord 那样使用 .find_each 或 .find_in_batches)。只要identity_map关闭,它就不会填满内存。

  • 关闭站点进行维护,再次运行迁移以捕获在过去几分钟内可能发生更改的任何金额字段(例如 Transaction.where(:updated_at.gt => 1 .hour.ago).each_with_index...

  • 在你的模型中注释掉field :amount, type: BigDecimal,你不想让mongoid再知道这个字段,并推送这个代码

  • 现在运行另一个脚本来重命名您的列(它会覆盖进程中任何旧的 BigDecimal 字符串值)。您可能需要对模型上需要旧字段的任何验证进行注释。

Mongoid.identity_map_enabled = false
Transaction.all.each_with_index do |t,i|
  puts i if i%1000==0
  t.rename :amount2, :amount
end

这是原子性的,不需要保存模型。

  • 更新模型以反射(reflect)新的列类型field :amount, type: Integer
  • 部署并恢复网站

如上所述,我认为有更好的方法,所以如果有人有一些提示,请分享。谢谢!

关于ruby-on-rails - 更改 Mongoid 中的字段类型而不丢失数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9389548/

相关文章:

ruby-on-rails - 使用 rvm 或 brightbox gems 升级到 ruby​​ 1.9.3

mysql - 我正在对一个 ruby​​ 站点进行工作备份,但不知道如何部署它

node.js - Nodejs中如何从不同模式获取数据

mongodb - 如何使用官方Go驱动程序在MongoDB中持久存储文件(小于16MB)

mongodb - 如何在不访问 Ubuntu 16.10 中的 Mongo shell 的情况下设置 featureCompatibilityVersion?

jquery - 将错误列表从Sinatra传递到jQuery的错误处理程序?

ruby-on-rails - 在新的 Rails 项目中从 SQLite 更改为 PostgreSQL

ruby-on-rails - ActiveRecord 和 Mogoid::Document : 关联

ruby-on-rails-3 - Mongoid动态查询

ruby-on-rails - 从Rails到 Sproutcore 的json格式