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がわりにするのって結構楽ちんなんですよね(小声)