用于大学笔记应用程序的高效数据库设计

时间:2019-06-06 12:51:37

标签: ruby-on-rails database-design

我正在设计一个Web应用程序,用于存储各种大学资料,例如笔记,电子书,试卷。

要求: 1.根据分支和学期获取笔记列表,例如如果选择了“计算机科学工程”和第1学期,则获取该分支和学期中的所有笔记。 2.根据学期和科目获取所有科目。

术语/我的设计: “注释”的类型可以为“电子书”,“试卷”,“实用文件”,“注释”。注意将具有标题,描述和文件附件。笔记将属于主题和类别。

类别:类似于“电子书”,“问题论文”等。它将带有标题。

分支:表示研究领域,例如“计算机科学与工程”,“电气工程”等。它将带有标题。分支机构将有多个学期。

主题:它将有一个标题。例如“数据结构”,“机器学习”等。

学期:表示通常的大学学期。一个学期将有多个科目。不同的学期可以共享科目。就像计算机科学第一学期的一门学科可能是电气工程第三学期的一门学科。

下面是我目前制作的模型。

class Note < ApplicationRecord
  belongs_to :user
  belongs_to :category
  belongs_to :subject
end
class Category < ApplicationRecord
  has_many :notes
end
class Branch < ApplicationRecord
  has_many :semesters
end
class Semester < ApplicationRecord
  has_and_belongs_to_many :subjects
  belongs_to :branch
end
class Subject < ApplicationRecord
  has_and_belongs_to_many :semesters
  has_many :notes
end

架构文件

create_table "branches", force: :cascade do |t|
    t.string "title"
    t.string "short_name"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "categories", force: :cascade do |t|
    t.string "title"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "notes", force: :cascade do |t|
    t.text "title"
    t.text "description"
    t.integer "user_id"
    t.integer "category_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.integer "subject_id"
    t.index ["category_id"], name: "index_notes_on_category_id"
    t.index ["subject_id"], name: "index_notes_on_subject_id"
    t.index ["user_id"], name: "index_notes_on_user_id"
  end

  create_table "semesters", force: :cascade do |t|
    t.integer "branch_id"
    t.string "title"
    t.integer "semester"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["branch_id"], name: "index_semesters_on_branch_id"
  end

  create_table "semesters_subjects", id: false, force: :cascade do |t|
    t.integer "subject_id", null: false
    t.integer "semester_id", null: false
    t.index ["semester_id", "subject_id"], name: "index_semesters_subjects_on_semester_id_and_subject_id"
    t.index ["subject_id", "semester_id"], name: "index_semesters_subjects_on_subject_id_and_semester_id"
  end

  create_table "subjects", force: :cascade do |t|
    t.string "title"
    t.string "short_name"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

目前,我正在使用这样的分支和学期来学习科目:

@subjects = Subject.joins(:semesters).where("semester_id = ? AND branch_id = ?", params[:semester], params[:branch]).pluck(:title, :id)

我觉得可以改进,因为我将参加所有请求。我最终想要的是创建一个过滤器UI,其中将“分支”,“学期”和“主题”作为选择来过滤Notes。

2 个答案:

答案 0 :(得分:0)

我认为您的设计很好,您可以尝试使用scope_method来简化过滤甚至使用类方法:

scope :branch_semester, -> {joins(:semesters).where("semester_id = ? AND 
     branch_id = ?", params[:semester], params[:branch]).pluck(:title, :id)}

答案 1 :(得分:0)

在这种情况下为什么不只获取Branch

@subjects = Branch.find(params[:branch]).subjects

分支机构和学期是一对一的,因此如果您具有分支机构ID,则不需要主题ID。请注意,我要subjectsBranch

为此,只需使用has_many :through

class Branch < ApplicationRecord
  has_many :semesters
  has_many :subjects, through: :semesters
end

我认为您的设计很好,这是标准的关系数据库。如果您真的要使用联接,则可以使用某种元数据,例如某些表中的JSON列,但是在这种情况下,IMO就是一个过大的选择。

过早的优化是万恶之源。如果您要缓存,则也不必担心。

因为您的控制器无需返回.subjects,而是可以返回分支:

@branch = Branch.find(params[:branch])

然后您认为

<% cache @branch do %>
  ... use @branch.subjects here, it will only be called once when generating the cache
<% end %>

查看Russian Doll Caching,以了解更多信息。