質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.04%

【Sequelize】assosiationで関連づけたmodelに個数を関連付けたい。

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 188

score -93

はじめに

Sequelizeでmodel作成の際、上記のようなデータ型の作成に悩んでしまったため、どのような手法があるかについて質問したかったため投稿しました。

例えばこういう例。

1食のメニューは材料データのなかから何種類か選んで作ります。
それぞれの材料を何個使うのかをメニューデータの中に保存したいとします。

const Ingredients = sequelize.define('Ingredients', {
  name: DataTypes.STRING,
  cost: DataTypes.INTEGER
});
const Menu = sequelize.define('Menu', {
  name: DataTypes.STRING
});
Menu.belongstoMany(Ingredients,{through:"Ingredient_Menu"})
Ingredients.belongstoMany(Menu,{through:"Ingredient_Menu"})

このとき、たとえば、Sequelizeを使わずArrayObjectで表すと、

[
 {
   id:1
   name:"豆腐",
   count:1,
 },
{
   id:2
   name:"みそ",
   count:1,
 },
]

上記の形で保存できれば可読性保守性が高い気がするんですが、
assosiationを用いると自由度が低く、上記のようなnameのところにIngredient情報を紐づけることができません。(以下のようになるはずです。)

こういったとき、どのようなデータ構造にするのが一番良いのでしょうか?

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

Sequelize で扱っているようなデータモデルをリレーショナルモデルと言います。
関係モデル - Wikipedia
このようなデータ構造を持ったデータベース(リレーショナルデータベースと言います)を実用的な速度で扱うためには JSON で保存するには向いていません。B木なんてものの改良したものをバイナリ形式で扱っています。JSON はあくまで人間が読みやすくするため作られたデータ形式です。機械のことは考えられていないので、データベースには使いにくいのです。

ではリレーショナルデータベースにデータを投入したり削除したりをどうするのかというと、専用のソフトを使います。Squelize の裏では SQLite や MySQL などが動いています。そしてそれぞれに専用のコマンドラインツールがあってそれを使って保守運用ができるのです。どのデータベースを使っているのかわかりませんが、手始めに直接データベースの中を覗いてどんなテーブルが作られているのか調べて回ってみると良いでしょう。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2021/01/06 17:11

    関係モデルとデータベースの関係についてよくわかりました。ありがとうございます。(ちなみにSQLiteを使用しています。)

    では、このようなリレーショナルデータベースにおいて質問文のような
    味噌汁メニューは豆腐1個と味噌1個だよ。といった情報を保存させるためにはどのような保存が適しているんでしょうか?
    MenuにはIngredients_MenuのIdが保存され、そこのIDから関係するIngredientsを引っ張ってくると思います。
    それのほかに、それぞれの個数をMenuに保存したいんです。(豆腐1個など)
    以下、思いついた構造3案
    ①Ingredient(リレーショナル)+ *Amount:Array(INTEGER)
    *Amountは個数の部分。ArrayとIngredientの対応方法が課題?
    ②Ingredient+Amount:Object{"ingredientName":{Amount:1},}
    わざわざオブジェクトをネストする必要がある?
    ③sequelizeモデルの作成(食材*個数のtoMenuMakeモデルの作成。
    リレーショナル化(Menuが引っ張ってくるのがtoMenuMake)。保守性は高いがわざわざここまで作成する必要がある?(デメリットとしてテーブル数がかなり増える。&Menu→toMenuMake→Ingredientと余計な経由が増える。))

    上記3パターンのどちらが一般的なのか知りたいです。
    使い分け等があればそれも併せて知りたく思います。

    キャンセル

  • 2021/01/06 17:28

    ③ の完全にリレーショナル化が一般的です。

    menu という id と name を持ったテーブルがあり、ingredient という id、name、cost からなるテーブルがあります。そして両者を紐付ける recipe とでも言いましょうか、menu_id と ingredient_id、amount からなるテーブルを作ります。このようにすることで recipe は menu_id と ingredient_id を通してリレーションを張ることが出来ます。リレーションを張ることで SQL を書く(もしくは ORM を使う)だけでメニューのコストを計算できるようになったりします。

    もちろんこれもおかたいということで JSON を JSON のまま保存できるデータベースも存在したりします。また、リレーショナルデータベースの中にも JSON をそのまま保存できるものも増えてきました。結局のところは「ケースバイケース」という言葉に落ち着くかと思うのですが、できるだけリレーションを張った形で運用したほうがデータベースとして何かと信頼が置けるのは間違いないでしょう。

    キャンセル

  • 2021/01/06 17:32

    丁寧な回答ありがとうございます!リレーショナル化が一般的なんですね!
    どの手法も結局面倒な場面が出てくるので悩んでしまっていました。
    データベースの信頼性を担保できるのであればリレーショナル化がいちばんですね!

    非常に助かりました。ありがとうございました!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.04%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る