新手问题 复杂的多对多数据关联设计

gxlonline · 2016年09月09日 · 最后由 IChou 回复于 2016年09月09日 · 3352 次阅读

有两个 model:people 和 attributes 每个人有很多个属性,每个属性下对应一个或多个人。

属性
张三 朋友 李四 王二

请问怎么设计数据表的关联比较好,用 mongodb 或 mysql。

这个是典型的多对多关系啊,无用 mongodb 或者 mysql http://guides.ruby-china.org/association_basics.html

属性可以是不同的种类?比如 盆友 亲人 对头 …

如果这种关系的种类是固定的,且不多,可以对每种关系当成普通的多对多来处理,比如用 has_and_belongs_to_many,由于是自关联,你需要手动指定链表表名

如果种类不固定或数量很多,可以建一个 relation 的 model(user_a,user_b,relation)来管理这些关系。当然这样查询的时侯你需要自己处理。你可以自己封装些方法来简化查询操作,也可以使用带条件的 has_many through 来声明关联,甚至可以在 User Model 中使用一点元编程实现和 rails 多对多关联一样的调用方式,从而淡化这个 relation 的存在。

ios 新客服端回复的,不能给你贴代码了

@easonlovewan @IChou 感谢你们的回答。

对提问做一点补充

属性的种类不固定且数量比较多,而且还存在反向查询。比如下面这种情况:

属性
A son B

这种情况

A.son  # => B

然后反过来

属性
B father A
B.father  # => A

需要注意的

有可能两人的关系是同一属性,比如朋友关系,正反都一样。有可能正反向不一样,比如父子,夫妻。 结合 @IChou 提到的建一个 relation 的 model,我现在想到的方法是: 在创建 A 的 son 是 B 这个关系时,同时检测 son 的对应属性是 father,然后同时创建一个反向 relation。 而且还需一个数据表来储存 father 与 son 的对应关系。

请问还有更好的实现吗?

mongo 的话直接记每个人的关系到人下

关系数据库用中间表

这种情况啊。。好像有点棘手

我觉得哈: 从对象间的关系来说,A 和 B 间的关系是相互的,是面对面的关系,而不是 关注某人 这种 面对背 的关系。所以我觉得如果是用两条数据的话,那基本所有记录都 double 了(就算是朋友这种你也需要冗余成两条数据,因为 relation 中的关系设计已经是单向了),为了保证不出现孤儿记录,维护成本会无形增加很多 所以我会在 relation 里这样设计

user_a user_b role_a role_b
A B father son
A C friend friend
class User

 # 定义所有的的关系,不介意性能的话,这里可以直接从数据库或缓存中取
  all_relations = %w(son father firends)

  all_relations.each do |role|
    define_method(role) do
      r = role.singularize

      relations = Relation.where(user_a: self.id, role_b: r)
              .or(Relation.where(user_b: self.id, role_a: r))
              .pluck(:user_a, :user_b)
      relate_ids = relations.flatten.reject{ |id| id == self.id }

      r == role ? User.find_by(id: relate_ids) : User.where(id: relation_ids)
    end
  end

end

A.son #=> B
B.son #=> nil
A.friends #=> [C]

不过这样一来,你也就基本彻底放弃使用 Rails 原有关联的可能性了 代码我没有验证过,你就把他当伪代码看吧。这里只有一个取操作,写的操作也可以这样写

Mongo 的话,感觉是不是会简单很多,上次用 Mongo 还是初学 Rails 的时候,已经很多不记得怎么用啦 有空我也得去补一下

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