こんにちは、MLBお兄さんこと松村です。
ただいま私は Microsoft Ignite 2023に参加するためにシアトルに来ています。
2023年9月ごろに Azure Cosmos DBのデザインパターン の GitHub リポジトリが公開されました。
このデザインパターンは Azure Cosmos DB for NoSQL を使用した、堅牢で効率的なアプリケーションを構築するときに役立つデザインパターンです。
リポジトリにはデザインパターンの説明のほか、C# でのサンプルコードも公開されているので、Azure Cosmos DB をよく使用する方は読んでおいて損はないでしょう。
今回の記事では、デザインパターンの最初に紹介されている属性配列 (Attribute Array) パターンについて読んでみたので解説します。
また、このパターンについてはマイクロソフトのブログでも解説されているため、あわせてご覧ください。
属性配列パターンを雑に言えば、類似したデータを含む複数の名前と値のペアを JSON 内の配列に含める、というものです。
と言ってもイメージしづらいと思うので、商品テーブルを用いて説明します。
例えばお店で販売されている商品は、サイズ、色、ブランド、価格、説明など、その商品に付随する属性情報を有します。
RDB でこのような情報を管理する場合は、2つのやり方があると思います。
- 商品テーブルに各属性としての列を持つ
- 商品テーブルに紐づく 1:多 の属性テーブルを作成する
どちらの方法が良いかは属性情報がどれくらいあるか、というケースにもよるかもしれませんが、保守性を考えると 2 を採用する場合が多いと思います。
erDiagram Products ||--o{ Sizes: has Products ||--o{ Colors: has Products ||--o{ Brands: has Products ||--o{ Prices: has Products ||--o{ Descriptions: has
Azure Cosmos DB for NoSQL でも属性配列パターンを採用することで、2つの利点を得ることができるとのことです。
- クエリの構築が簡素・簡潔になり、バグを発生しにくくする
- インデックス作成の効率が向上し、パフォーマンスが向上する
それでは、1つの商品についての各サイズの在庫数を例にして検討してみます。
在庫数をプロパティに持つ
RDB でいう「商品テーブルに各属性としての列を持つ」方法のほうです。
Cosmos DB の JSON オブジェクトは以下を例とします・
{ "id": "89e89f1a-3c9d-c043-7c3f-8522d6a1ef01", "productId": "89e89f1a-3c9d-c043-7c3f-8522d6a1ef01", "name": "Sleek Fresh Shoes", "category": "Computers, Outdoors & Shoes", "price": 895.37, "sizeSmall": 24, "sizeMedium": 61, "sizeLarge": 51 }
サイズごとの在庫数で絞り込むときのクエリは下記のようになり、サイズごとに条件を指定する必要があります。
SELECT VALUE p FROM products p WHERE p.sizeSmall >= 55 OR p.sizeMedium >= 55 OR p.sizeLarge >= 55
XL などの新しいサイズが追加されるときは、プロパティの追加とクエリの修正の2つの作業が発生し、どちらも漏れなく行う必要があります。
属性配列パターンを適用する
ここで属性配列パターンを適用してみます。
RDB でいう「商品テーブルに紐づく 1:多 の属性テーブルを作成する」方法の方です。
JSON オブジェクトは、以下のような構成となります。(名前などは変えています)
{ "id": "76841ca4-679b-5cd9-406f-28216d30d71e", "productId": "76841ca4-679b-5cd9-406f-28216d30d71e", "name": "Practical Metal Sausages", "category": "Jewelery", "price": 480.70, "sizes": [ { "name": "Small", "count": 24 }, { "name": "Medium", "count": 96 }, { "name": "Large", "count": 80 } ] }
サイズごとの在庫数で絞り込むときのクエリは下記のようになります。
SELECT VALUE p FROM products p JOIN s IN p.sizes WHERE s.count >= 55
XL などの新しいサイズが追加されるときは、"sizes"
の配列にオブジェクトを追加するだけで済み、クエリを修正する必要がありません。
"sizes": [ { "name": "Small", "count": 24 }, { "name": "Medium", "count": 96 }, { "name": "Large", "count": 80 }, { "name": "Extra Large", "count": 60 } ],
上記のようにクエリが簡潔になるメリットがあるため、属性配列パターンは効果があるということが理解できました。
このパターンは Azure Cosmos DB をよく使う方であれば、馴染みがあるかと思います。
デザインパターンのリポジトリではサンプルコードも公開されていますので、実際にコードを眺めてみるとより理解できるでしょう。