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

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

ただいまの
回答率

89.08%

イイねの対象が複数存在する場合のテーブル設計について

受付中

回答 2

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 423
退会済みユーザー

退会済みユーザー

イイねの対象が複数存在する場合のテーブル設計について相談できる人がまわりにいないので困っています。

例えばmediumdev.toでは「投稿」と「投稿についたコメント」に対してイイねができます。
ユーザーは投稿/コメントについたイイね数が確認できるのはもちろんのこと、自分がイイねした投稿やコメントはマイページで確認できます。
今回の要件(やりたいこと)はこちらと同じようなことになります。

その要件を実現するために、自分なりにテーブル設計をしてみましたが、以下の懸念点が出てきました。

  • likesテーブルで外部キーがusersにしかはれない
  • データ量が膨大に膨れ上がりそうな予感

こういったケースの場合どういった設計にするべき(するのが良い)でしょうか?
何か少しでもアドバイスいただけると幸いです。

関連テーブルの構造イメージ
CREATE TABLE `users` (
  `id` varchar(255),
  `name` varchar(255),
  PRIMARY KEY (`id`)
)

CREATE TABLE `posts` (
  `id` varchar(255),
  `title` varchar(255),
  `content` varchar(255),
  `author_id` varchar(255),
  PRIMARY KEY (`id`),
  FOREIGN KEY (`author_id`) REFERENCES `users` (`id`)
)

CREATE TABLE `comments` (
  `id` varchar(255),
  `post_id` varchar(255),
  `author_id` varchar(255),
  `content` varchar(255),
  PRIMARY KEY (`id`),
  FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`),
  FOREIGN KEY (`author_id`) REFERENCES `users` (`id`)
)

CREATE TABLE `likes` (
  `id` varchar(255),
  `object_type` varchar(255),
  `object_id` varchar(255),
  `user_id` varchar(255),
  PRIMARY KEY (`id`),
  FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)
)
likesテーブルの中身イメージ
ID ユーザーID オブジェクトタイプ(テーブル名) オブジェクトID(レコードID) ※説明用
1 user1 posts post1 user1がpost1に対してイイね
2 user2 posts post9 user2がpost9に対してイイね
3 user1 comments comment1 user1がcomment1に対してイイね
4 user1 comments comment5 user1がcomment5に対してイイね
5 user1 comments comment13 user1がcomment13に対してイイね
補足追記
  • 将来的に、投稿人物(users)に対してイイね機能を追加したり、投稿写真(photos)に対してイイね機能を追加したりと、イイねの対象が増える可能性があります。
  • RDBMS(MySQL5.7を利用想定)を前提に考えております。
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

0

ちょっと状況がわからないですが、イイねをするのが文章に対してですから
その文書のdocumentidと自分のuseridを紐付ける中間テーブルがあればいいのでは?
子文書をイイねすると親文書もマイページで閲覧したいなら、子文書に
親文書のdocumentidを属性として持たせることです

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/12/20 16:27

    ご回答有り難うございます。

    > イイねをするのが文章に対してですからその文書のdocumentidと自分のuseridを紐付ける中間テーブルがあればいいのでは?

    理解不足で申し訳ないですが、postsテーブルとcommentsテーブルを1つにして(わけずに)documentsテーブルみたいなものを1つ用意して、そのテーブルとusersテーブルの中間テーブルを作成するという設計でしょうか?

    キャンセル

0

likesテーブルで外部キーがusersにしかはれない

異なるテーブルを一元で管理する以上必ずそうなります。
仮に管理テーブルを用意して一意なIDを払い出すようにすると、likesテーブルからその管理テーブルに対しては、外部キーが設定できますが、管理テーブルには外部キーは設定できないのですから。

根本にあるのはテーブルが別ということです。
postcommentは主にテキストを扱うのですからこれをpostcommentの識別を持たせ一つのテーブルに纏めると、likesテーブルに外部キーが設定できることになります。

データ量が膨大に膨れ上がりそうな予感

正規化に照らすとそうなってしまうものは当然あります。
そのような場合に正規化を緩める方法として、配列などに折りたたむ方法があります。
配列の扱いとしてはjson形式であったりカンマ区切りの文字列だったり、純粋な配列だったり、DBMSのサポートする機能に依存します。
配列とする事のメリットとしては、別テーブルとした場合の結合コストやキー部分の容量を削減できる事がありますが、デメリットとしては、検索や更新が簡潔なSQLとはならない点です。

特に検索について、全行から検索するような要件がある場合は、最低限、(配列を含めて)その型に対する検索機能を有したRDBMSである事が選定条件になるでしょう。

尤も、RDBMSではなくNoSQLという選択なら上記のようなことは無い訳ですが。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/12/20 16:22 編集

    ご回答有り難うございます。

    > 根本にあるのはテーブルが別ということです。

    なるほどです。
    ただ、投稿人物(users)に対してイイね機能を追加したり、投稿写真(photos)に対してイイね機能を追加したりと、イイねの対象が増える可能性が現実的にあります。

    そういった将来的な拡張性を考慮すると別テーブルにしておいたほうが良いかと思いました。
    そうなると以下の二択だと考えました。
    1. 私が考えた設計をベースとして、saziさんの仰る「配列などに折りたたむ方法」を検討する
    2. イイねの対象(users, photos)が増えるたびに中間テーブルを増やす(例:user_likes, photo_likes...)

    saziさん(ベテランの方)なら、こういった問題にどういった判断基準で1 or 2を選定されるのですか?
    または3や4...といった他の選択(上記以外の設計)をされるのでしょうか?

    > 尤も、RDBMSではなくNoSQLという選択なら上記のようなことは無い訳ですが。

    こちらはすみませんがRDBMS前提でお願いいたしますm__m

    キャンセル

  • 2018/12/20 16:47 編集

    1と2は判断基準が別物です。
    1は第2正規化を緩める事ですし、2はエンティティの分割の話です。
    1にについては既に経験があり、配列にする事で性能と容量を改善する事ができました。
    但し、配列の扱いが得意なpostgresで、SQLのチューニング(配列を展開して検索するなど)を行った上で実現したものですけど。

    2についても保守を不要とする汎用的な扱いを行うために実装したことはあります。
    予めオブジェクトの種類ごとのパーティションにしておけば、性能的には物理テーブルを分けるのと変わりません。※postgresは実質物理的には別テーブルで構成される。
    但し、共通化するために、逆にイレギュラーな部分を分割するというのは考慮ておいた方が良いですけど。

    キャンセル

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

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

関連した質問

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