如何在不丢失任何数据的情况下运行迁移以更改Mongoid / MongoDB中字段的类型?
在我的情况下,我试图将BigDecimal(存储为字符串)转换为Integer来存储一些钱。我需要将字符串十进制表示转换为整数的美分。我不想丢失现有数据。
我假设步骤可能是这样的:
amount2
amount
转换为amount2
的正确值amount
,并且从用户的角度来看没有停机时间)amount
字段amount
并将amount2
重命名为amount
amount
为整数看起来Mongoid提供rename
方法:http://mongoid.org/docs/persistence/atomic.html#rename
但我有点困惑如何使用它。如果您有一个名为amount2
的字段(并且您已经删除了amount
),那么您是否只运行Transaction.rename :amount2, :amount
?然后我想这会立即打破基础表示,所以你必须在那之后重启你的应用服务器?如果您在amount
仍然存在时运行该怎么办?是否会被覆盖,失败或尝试自行转换?
谢谢!
答案 0 :(得分:3)
好的,我完成了。我认为有一种更快的方式使用mongo控制台,如下所示: MongoDB: How to change the type of a field?
但是我无法使转换工作,因此在rails控制台中选择了这种速度较慢的方法,停机时间更长。如果有人有更快的解决方案,请发布。
amount2
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游标,你不需要使用.find_each或.find_in_batches,如使用mysql的常规activerecord)。只要identity_map关闭,它就不会填满内存。
关闭网站进行维护,再次运行迁移以捕获最近几分钟内可能发生变化的任何金额字段(类似Transaction.where(:updated_at.gt => 1.hour.ago).each_with_index...
在您的模型中注释field :amount, type: BigDecimal
,您不希望mongoid再次知道此字段,并推送此代码
的
Mongoid.identity_map_enabled = false
Transaction.all.each_with_index do |t,i|
puts i if i%1000==0
t.rename :amount2, :amount
end
这是原子的,不需要在模型上保存。
field :amount, type: Integer
如前所述,我认为有更好的方法,所以如果有人有一些提示请分享。谢谢!