更改Mongoid中的字段类型而不会丢失数据
如何在不丢失任何数据的情况下运行迁移以更改Mongoid / MongoDB中字段的类型?
在我的情况下,我试图从BigDecimal(存储为字符串)转换为整数来存储一些钱。 我需要将字符串十进制表示转换为整数的美分。 我不想丢失现有数据。
我假设步骤可能是这样的:
- 使用新名称创建新的整数字段,例如
amount2
- 部署到生产并运行迁移(或rake任务),将每个
amount
转换为amount2
的正确值 - (这整个时间现有代码仍在使用
amount
,从用户的角度来看没有停机时间) - 将网站停下来进行维护,再次运行迁移以捕获在过去几分钟内可能已更改的任何
amount
字段 - 删除
amount
并将amount
重命名为amount
- 部署期望
amount
为整数的新代码 - 带回网站
看起来Mongoid提供了一种rename
方法: http ://mongoid.org/docs/persistence/atomic.html#rename
但我有点困惑如何使用它。 如果您有一个名为amount2
的字段(并且您已经删除了amount
),您是否只运行Transaction.rename :amount2, :amount
? 然后我想这会立即打破基础表示,所以你必须在那之后重启你的应用服务器? 如果您在amount
仍然存在的情况下运行会发生什么? 是否会被覆盖,失败或尝试自行转换?
谢谢!
好的,我完成了。 我认为有一种更快的方式使用mongo控制台: MongoDB:如何更改字段的类型?
但我无法使转换工作,因此在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
请注意.all.each工作正常(因为mongodb游标,你不需要像使用mysql的常规activerecord那样使用.find_each或.find_in_batches)。 只要identity_map关闭,它就不会填满内存。
-
将网站停下来进行维护,再次运行迁移以捕获在过去几分钟内可能已更改的任何数量的字段(例如
Transaction.where(:updated_at.gt => 1.hour.ago).each_with_index...
-
注释掉
field :amount, type: BigDecimal
模型中的field :amount, type: BigDecimal
,你不希望mongoid再次知道这个字段,并推送此代码 - 现在运行另一个脚本来重命名您的列(它会覆盖进程中任何旧的BigDecimal字符串值)。 您可能需要评论模型上对旧字段的任何validation。
Mongoid.identity_map_enabled = false Transaction.all.each_with_index do |t,i| puts i if i%1000==0 t.rename :amount2, :amount end
这是primefaces的,不需要在模型上保存。
- 更新模型以反映新的列类型
field :amount, type: Integer
- 部署并恢复网站
如上所述,我认为有更好的方法,所以如果有人有一些提示请分享。 谢谢!