簡體   English   中英

如何使用 ruby 更新一批 S3 對象的元數據?

[英]How do I update a batch of S3 objects' metadata using ruby?

我需要更改 S3 上成百上千個對象的一些元數據(內容類型)。 使用 ruby 執行此操作的好方法是什么? 據我所知,無法使用fog.io僅保存元數據,必須重新保存整個 object。 似乎使用官方 sdk 庫需要我為這一項任務滾動包裝環境。

沒錯,官方 SDK 允許您修改對象元數據,而無需再次上傳。 它所做的是復制對象,但它位於服務器上,因此您無需下載文件並重新上傳。

包裝器很容易實現,比如

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

在 v2 API 中,您可以使用帶有:metadata:metadata_directive => 'REPLACE'選項的Object#copy_from()Object.copy_to()來更新對象的元數據,而無需從 S3 下載它。

Joost 的要點中的代碼拋出此錯誤:

Aws::S3::Errors::InvalidRequest:此復制請求是非法的,因為它試圖將對象復制到自身而不更改對象的元數據、存儲類別、網站重定向位置或加密屬性。

這是因為默認情況下,AWS 會忽略隨復制操作提供的:metadata ,因為它會復制元數據。 如果我們想就地更新元數據,我們必須設置:metadata_directive => 'REPLACE'選項。

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

這是我最近用來執行元數據更新操作的完整、有效的代碼片段:

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

對於未來的讀者,這里是使用 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

經過一番搜索,這似乎對我有用

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

使用 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

這個 API 現在似乎可用:

Fog::Storage.new({
  :provider                 => 'AWS',
  :aws_access_key_id        => 'foo',
  :aws_secret_access_key    => 'bar',
  :endpoint => 'https://s3.amazonaws.com/',
  :path_style => true
}).put_object_tagging(
  'bucket_name',
  's3_key',
  {foo: 'bar'}
)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM