Rails 关于扩展字段的设计问题

shoushen · 2015年12月14日 · 最后由 angelfan 回复于 2015年12月15日 · 3726 次阅读

问一下,自己一个业余的小项目,希望实现用户对项目属性的自定义,可以新增字段或者修改、删除字段,请问如何设计数据库比较好? 采用 MongoDB 或者利用 PostgreSQL 的 JSONB 数据类型来实现是否会简单些? 主要考虑实现的简洁和使用的简单。

本人用的是最土的方案,没用 MongoDB,没用 JSONB,用冗余字段。

# 表名:客户资料表
# 描述:t1, s1等这些列的定义见columns表。
class CreateCustomers < ActiveRecord::Migration
  def change
    create_table :customers do |t|
      t.belongs_to  :company, index: true
      t.belongs_to  :salesman
      t.integer     :t1
      t.integer     :t2
      t.integer     :t3
      t.integer     :t4
      t.integer     :t5
      t.integer     :t6
      t.string      :s1 #这是手机号,如果存在效率问题,可以考虑用bigint
      t.string      :s2
      t.string      :s3
      t.string      :s4
      t.string      :s5
      t.date        :d1
      t.date        :d2
      t.date        :d3
      t.datetime    :dt1
      t.datetime    :dt2
      t.integer     :t7
      t.integer     :t8
      t.integer     :t9
      t.string      :s6
      t.string      :s7
      t.string      :s8
      t.string      :s9
      t.string      :s10
      t.string      :s11
      t.string      :s12
      t.string      :s13
      t.string      :s14
      t.string      :s15
      t.string      :s16
      t.string      :s17
      t.string      :s18
      t.string      :s19
      t.string      :s20
      t.timestamps
    end
  end
end

# 表名:自定义数据列
class CreateColumns < ActiveRecord::Migration
  def change
    create_table :columns do |t|
      t.belongs_to :company, index: true
      t.string     :name # 值是s3, t1, d2, dt2这样的数据。's'起头表示输入型, 't'起头表示下拉选框型(下拉选项值需要关联options表), 'd'起头表示日期型,'dt'起头表示时间型;N表示第几个
      t.string     :title
      t.integer    :width
      t.timestamps
    end
  end
end

#   Column中类型为“下拉选项”的具体选项
class CreateOptions < ActiveRecord::Migration
  def change
    create_table :options do |t|
      t.belongs_to  :company, index: true
      t.integer     :tid #Column表的t开头的字段id,如't2',则此处值为2
      t.integer     :value
      t.string      :text
    end
  end
end
2 楼 已删除

这个显然无法满足要求啊。我是希望实现每个项目的管理者对项目的字段进行自定义。。。。。

#3 楼 @shoushen 搞个关联表不就行了么?

@chenge 那样的做好感觉不简洁啊。表里面要存项目 ID,属性 ID,属性值,如果一个项目 10 个属性,10000 个项目就有 100000 个属性值。。。。。

可以根据的不同的类型建立不同表。

加一个字段,保存 json 数据,如何?

@chenge @hooopo @rubyist518 @gazeldx 我目前的想法是用 JSONB 字段来存每个项目的属性和值,在加个表管理每个项目的属性。不知道可行否?征求一下大家意见。

关系型数据库的解决方案叫Entity–attribute–value model (EAV) 主要有三个表:

  1. entities
  2. attributes 名称 类型等信息
  3. values entity_id, attribute_id, value 不过缺点很明显:
  4. 数据增长很快
  5. 索引效能低,索引奇大
  6. 查询困难,很多的 join table
  7. 很早就要考虑分表。

后来用上 PostgreSQL 的 jsonb 格式,jsonb 能够加 gin 索引,空间和查询性能都完胜。对上面的 EVA 作一点优化,变成两个表

  1. attributes
  2. entities. 里面有一个 jsonb 类型的 values 字段

MongoDB 没考虑,我的经验是大部分的数据都是 schema 的。schemaless 在 dev 时很爽,但上线后迭代也是要做 migrations

为啥不考虑纵表呢

#3 楼 @shoushen 我的方案你还没有认真的思考,就说不能满足你的要求。请认真思考。我公司的项目就是让企业自己定义客户资料,和你的需求本质的一样的。 我个人不建议用 JSONB,因为实现一下你就知道:代码量大,而且可能会有性能问题(同时我自己这种方案研究还不够深入)。 如果你足够黑客,建议用 MongoDB。

要啥自行车啊,非关联性字段预留就可以了。@gazeldx 的方案是老技术人员的常用方法。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号