如何更新一批 S3 对象?使用 ruby​​ 的元数据?

发布于 2025-01-05 22:00:00 字数 254 浏览 6 评论 0原文

我需要更改 S3 上数百或数千个对象的一些元数据(内容类型)。用红宝石来做到这一点的好方法是什么?据我所知,无法仅使用 fog.io 保存元数据,必须重新保存整个对象。似乎使用 官方 sdk 库 需要我为此滚动一个包装器环境一项任务。

I need to change some metadata (Content-Type) on hundreds or thousands of objects on S3. What's a good way to do this with ruby? As far as I can tell there is no way to save only metadata with fog.io, the entire object must be re-saved. Seems like using the official sdk library would require me rolling a wrapper environment just for this one task.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

半暖夏伤 2025-01-12 22:00:00

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

包装器很容易实现,比如

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

You're right, the official SDK lets you modify the object metadata without uploading it again. What it does is copy the object but that's on the server so you don't need to download the file and re-upload it.

A wrapper would be easy to implement, something like

bucket.objects.each do |object|
  object.metadata['content-type'] = 'application/json'
end
猫七 2025-01-12 22:00:00

在 v2 API 中,您可以将 Object#copy_from()Object.copy_to():metadata:metadata_directive 结合使用=> “REPLACE”选项可更新对象的元数据,而无需从 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

In the v2 API, you can use Object#copy_from() or Object.copy_to() with the :metadata and :metadata_directive => 'REPLACE' options to update an object's metadata without downloading it from S3.

The code in Joost's gist throws this error:

Aws::S3::Errors::InvalidRequest: This copy request is illegal because
it is trying to copy an object to itself without changing the object's
metadata, storage class, website redirect location or encryption
attributes.

This is because by default AWS ignores the :metadata supplied with a copy operation because it copies metadata. We must set the :metadata_directive => 'REPLACE' option if we want to update the metadata in-place.

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

Here's a full, working code snippet that I recently used to perform metadata update operations:

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",
)

For easy re-use:

def update_metadata(s3_object, new_metadata = {})
  s3_object.copy_to(s3_object,
    :metadata => new_metadata
    :metadata_directive => "REPLACE"
  )
end
小嗷兮 2025-01-12 22:00:00

对于未来的读者,这里有一个使用 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

For future readers, here's a complete sample of changing stuff using the Ruby aws-sdk v1 (also see this Gist for a aws-sdk v2 sample):

# 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
匿名的好友 2025-01-12 22:00:00

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

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

after some search this seems to work for me

obj.copy_to(obj, :metadata_directive=>"REPLACE", :acl=>"public-read",:content_type=>"text/plain")
朱染 2025-01-12 22:00:00

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

Using the sdk to change the content type will result in x-amz-meta- prefix. My solution was to use ruby + aws cli. This will directly write to the content-type instead of 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
黄昏下泛黄的笔记 2025-01-12 22:00:00

该 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'}
)

This API appears to be available now:

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'}
)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文