S3のKey命名について


S3のバケットに色々なデータを置いていくと、ちょいちょい命名に悩むことがあります。
本記事は命名規則、というほど大袈裟なものではありませんが、「こうしたら楽だった」という経験則についてのお話です。

REST的な命名は意外と困る

RESTに慣れていると、S3もそれに合わせて以下のような命名にしたくなります。

dogs/{dogId}/age.json
dogs/{dogId}/name.json
dogs/{dogId}/weight.json

idと、その属性を保存したいようなケースですね。
この場合、特定のidに対する属性は簡単に取得することができます。
ListObjectsV2のprefixで、dogs/{dogId}/を指定すればすぐですね。

ただ、開発を続けていると「全てのdogsのageを知りたい」ってケースも当然のように出てきて、そうなると対象のdogIdを全て知っている必要があり、ちょっと面倒なことになります。

ではどうしようか

シンプルな話ですけども、属性をできる限り前に記載し、一意とする識別子は後ろにするを基本にすると便利です。

dogs/ages/{dogId}.json
dogs/names/{dogId}.json
dogs/weights/{dogId}.json

って感じですね。
この書き方であれば、「全てのdogsのageを知りたい」というケースはdogs/ages/のprefix指定で取得可能です。

とはいえ、当然の如く

「おいおい、それじゃ、特定のidに対する全ての属性を取得する」ってケースに対応できなくなるがな」

って話になりますが、属性は基本的にそんな大量にない&あらかじめ知っているはず、という前提にて、「全ての属性について知る」と「全てのidについて知る」のどちらが楽か、というと、やはり前者になるかと思うわけです。

例外的なケースは当然あろうとは思いますが、何か新しいファイルを置く必要が出てきた際、毎回「こうかなぁ、、、?」って悩まずとも、この基本ルールを適用すると話がサクサク進んで良いかなと思っております。

一意とする識別子が複数ある時はどうすんの?

例えばこんなケースもありますよね。

breeders/{breederId}/dogs/{dogId}/age.json

これも悩ましい話ではあるのですが、属性をできる限り前に記載し、一意とする識別子は後ろにするに従うとこうなります。

dogs/ages/breeder.{breederId}/dog.{dogId}.json

わからなくはないです。でも、なんか、ちょっと気持ち悪い、、
でも、いつか「特定のbreederIdに所属する全てのdogのageを知りたい」って要件が出てきた時、これは結構助かります。

じゃあさらに一意となる値が複数出てきたらどうするの?

仰ることはわかります。こういうことですよね。

organizations/{organizationId}/breeders/{breederId}/dogs/{dogId}/age.jsonn

OK、わかったわかった、こうだろう?

dogs/ages/organization.{organizationId}/breeder.{breederId}/dog.{dogId}.json

問題は解決しました。これなら「特定のorganizationに所属するdogの全てのage」も、「特定のorganizationに所属する特定のbreederが育てたdogの全てのage」も取得できます。

しかしここでまた新しい要件が。
「breederは複数のorganizationに所属していることがある。特定のbreederが育てたdogの属性を全部知りたいんだ」

え?organizationIdは全部わかるんですよね。え?取得するのにめちゃくちゃ負荷がかかるから使いたくない? 無茶言うな

無茶なのは、、、?

全く、どんどん要件変えやがって。困ったもんだ。無茶ばっかりだ、、

という気もしますが、まぁ、ぶっちゃけるとそんな複雑な検索要件が出てくるものをS3で扱おうって前提が間違っていた、という可能性も大いにあります。DynamoDBを使え

そうです、本記事は、安いからついS3をDynamoDBの代替にしたくなる貧乏性が産んだ経験則だったのです、、、!

という締まらない結論にて締めたいと思います。
ここまで読んでいただいて、ありがとうございました。

でも、要件が固まってるタイプのデータなら、S3をDBがわりにするのって結構楽ちんなんですよね(小声)