如何将图像迁移到 Rails 中的新字段?
How to migrate images to new field in Rails?
我在 Rails 5.2.3 上使用 Ruby,用于图像的 Mongoid、Attachinary 和 Cloudinary。
class User
include Mongoid::Document
has_attachment :image, accept: [:jpg, :png, :gif]
field :pic, type: String
before_update :migrate_images
def migrate_images
self.image_url = self.pic
end
end
图像作为链接保存在 pic 字段中。
现在我使用这个代码,问题是这需要很长时间并且不是所有的图像都被保存。
User.where(:pic.exists => true).all.each &:update
日志
irb(main):001:0> User.where(:pic.exists => true).all.each &:update
=> #<Mongoid::Contextual::Mongo:0x00007ffe5a3f98e0 @cache=nil, @klass=User, @criteria=#<Mongoid::Criteria
selector: {"pic"=>{"$exists"=>true}}
options: {}
class: User
embedded: false>
, @collection=#<Mongo::Collection:0x70365213493680 namespace=link_development.users>, @view=#<Mongo::Collection::View:0x70365213493380 namespace='link_development.users' @filter={"pic"=>{"$exists"=>true}} @options={"session"=>nil}>, @cache_loaded=true>
User.where(:pic.exists => true).all.each &:update
这很慢,因为 .all.each
将所有匹配的用户加载到内存中,find_each
在内存上更有效一些,因为它会分批加载,但仍然浪费时间和内存将每个对象加载到内存中并将其变成一个对象以复制一个属性。然后它 运行 是每个单独的 update
。
相反,您可以在单个查询中完全在数据库中执行此操作。
如果打算从 User.pic
复制到 User.image_url
,您可以在一条语句中完成此操作。
# Find all the users who do not already have an image_url set
User.where(image_url: nil)
# Set their image_url to be their pic.
.update_all("image_url = pic")
这将 运行 单个查询:
update users
set image_url = pic
where image_url is null
没有必要同时检查缺少 pic
的用户,因为将 nil 设置为 nil 没有坏处,而且更简单的搜索可能会更快。但是如果你喜欢检查,你可以使用 where.not
。 Users.where(image_url: nil).where.not(pic: nil)
我在 Rails 5.2.3 上使用 Ruby,用于图像的 Mongoid、Attachinary 和 Cloudinary。
class User
include Mongoid::Document
has_attachment :image, accept: [:jpg, :png, :gif]
field :pic, type: String
before_update :migrate_images
def migrate_images
self.image_url = self.pic
end
end
图像作为链接保存在 pic 字段中。 现在我使用这个代码,问题是这需要很长时间并且不是所有的图像都被保存。
User.where(:pic.exists => true).all.each &:update
日志
irb(main):001:0> User.where(:pic.exists => true).all.each &:update
=> #<Mongoid::Contextual::Mongo:0x00007ffe5a3f98e0 @cache=nil, @klass=User, @criteria=#<Mongoid::Criteria
selector: {"pic"=>{"$exists"=>true}}
options: {}
class: User
embedded: false>
, @collection=#<Mongo::Collection:0x70365213493680 namespace=link_development.users>, @view=#<Mongo::Collection::View:0x70365213493380 namespace='link_development.users' @filter={"pic"=>{"$exists"=>true}} @options={"session"=>nil}>, @cache_loaded=true>
User.where(:pic.exists => true).all.each &:update
这很慢,因为 .all.each
将所有匹配的用户加载到内存中,find_each
在内存上更有效一些,因为它会分批加载,但仍然浪费时间和内存将每个对象加载到内存中并将其变成一个对象以复制一个属性。然后它 运行 是每个单独的 update
。
相反,您可以在单个查询中完全在数据库中执行此操作。
如果打算从 User.pic
复制到 User.image_url
,您可以在一条语句中完成此操作。
# Find all the users who do not already have an image_url set
User.where(image_url: nil)
# Set their image_url to be their pic.
.update_all("image_url = pic")
这将 运行 单个查询:
update users
set image_url = pic
where image_url is null
没有必要同时检查缺少 pic
的用户,因为将 nil 设置为 nil 没有坏处,而且更简单的搜索可能会更快。但是如果你喜欢检查,你可以使用 where.not
。 Users.where(image_url: nil).where.not(pic: nil)