【问题标题】:How do I update a batch of S3 objects' metadata using ruby?如何使用 ruby​​ 更新一批 S3 对象的元数据?
【发布时间】:2012-02-14 16:53:36
【问题描述】:

我需要更改 S3 上成百上千个对象的一些元数据(内容类型)。用红宝石做这件事的好方法是什么?据我所知,没有办法只使用fog.io 保存元数据,必须重新保存整个对象。似乎使用 the official sdk library 需要我为这项任务滚动一个包装器环境。

【问题讨论】:

    标签: ruby amazon-s3 fog


    【解决方案1】:

    你说得对,官方 SDK 允许你修改对象元数据而无需再次上传。它的作用是copy the object,但它在服务器上,因此您无需下载文件并重新上传。

    包装器很容易实现,例如

    bucket.objects.each do |object|
      object.metadata['content-type'] = 'application/json'
    end
    

    【讨论】:

    【解决方案2】:

    在 v2 API 中,您可以使用 Object#copy_from()Object.copy_to():metadata:metadata_directive => 'REPLACE' 选项来更新对象的元数据,而无需从 S3 下载它。

    Joost's gist 中的代码抛出这个错误:

    Aws::S3::Errors::InvalidRequest:此复制请求是非法的,因为 它试图将对象复制到自身而不更改对象的 元数据、存储类、网站重定向位置或加密 属性。

    这是因为默认情况下 AWS 会忽略随复制操作提供的 :metadata,因为它会复制元数据。如果我们想就地更新元数据,我们必须设置 :metadata_directive => 'REPLACE' 选项。

    http://docs.aws.amazon.com/sdkforruby/api/Aws/S3/Object.html#copy_from-instance_method

    这是我最近用来执行元数据更新操作的完整工作代码 sn-p:

    require 'aws-sdk'
    
    # S3 setup boilerplate
    client = Aws::S3::Client.new(
      :region => 'us-east-1',
      :access_key_id => ENV['AWS_ACCESS_KEY'],
      :secret_access_key => ENV['AWS_SECRET_KEY'], 
    )
    s3 = Aws::S3::Resource.new(:client => client)
    
    # Get an object reference
    object = s3.bucket('my-bucket-name').object('my-object/key')
    
    # Create our new metadata hash. This can be any hash; in this example we update
    # existing metadata with a new key-value pair.
    new_metadata = object.metadata.merge('MY_NEW_KEY' => 'MY_NEW_VALUE')
    
    # Use the copy operation to replace our metadata
    object.copy_to(object,
      :metadata => new_metadata,
    
      # IMPORTANT: normally S3 copies the metadata along with the object.
      # we must supply this directive to replace the existing metadata with
      # the values we supply
      :metadata_directive => "REPLACE",
    )
    

    为了便于重复使用:

    def update_metadata(s3_object, new_metadata = {})
      s3_object.copy_to(s3_object,
        :metadata => new_metadata
        :metadata_directive => "REPLACE"
      )
    end
    

    【讨论】:

    • 添加缓存控制使用:object.copy_to(object, cache_control: 'public,max-age=333333', metadata_directive: 'REPLACE')
    • V3 API似乎不再支持这个了,我觉得v3中的copy_from可能只是复制元数据,不允许替换? docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/…
    【解决方案3】:

    对于未来的读者,这是使用 Ruby aws-sdk v1 更改内容的完整示例(另请参阅 Gist 以获取 aws-sdk v2 示例):

    # Using v1 of Ruby aws-sdk as currently v2 seems not able to do this (broken?).
    require 'aws-sdk-v1'
    
    key = YOUR_AWS_KEY
    secret = YOUR_AWS_SECRET
    region = YOUR_AWS_REGION
    
    AWS.config(access_key_id: key, secret_access_key: secret, region: region)
    s3 = AWS::S3.new
    bucket = s3.buckets[bucket_name]
    bucket.objects.with_prefix('images/').each do |obj|
      puts obj.key
      # Add  metadata: {} to next line for more metadata.
      obj.copy_from(obj.key, content_type: obj.content_type, cache_control: 'max-age=1576800000',  acl: :public_read)
    end
    

    【讨论】:

    • 您的要点说 v2 示例似乎不起作用,并暗示它可能是 SDK 中的一个错误...我认为您还没有解决它?
    • 不。只需使用最新版本的 v2 试试要点 :)
    • v2 版本也不适合我。我已经用我的解决方案评论了要点(重新上传每个文件)。
    【解决方案4】:

    经过一番搜索,这似乎对我有用

    obj.copy_to(obj, :metadata_directive=>"REPLACE", :acl=>"public-read",:content_type=>"text/plain")
    

    【讨论】:

      【解决方案5】:

      使用 sdk 更改内容类型将导致 x-amz-meta- 前缀。我的解决方案是使用 ruby​​ + aws cli。这将直接写入content-type 而不是x-amz-meta-content-type

      ids_to_copy = all_object_ids
      ids_to_copy.each do |id|
          object_key = "#{id}.pdf"
          command = "aws s3 cp s3://{bucket-name}/#{object_key} s3://{bucket-name}/#{object_key} --no-guess-mime-type --content-type='application/pdf' --metadata-directive='REPLACE'"
          system(command)
      end
      

      【讨论】:

        猜你喜欢
        • 2021-09-26
        • 1970-01-01
        • 1970-01-01
        • 2017-07-16
        • 2011-06-12
        • 2012-08-04
        • 2018-09-20
        • 1970-01-01
        • 2021-03-13
        相关资源
        最近更新 更多