SQL查询通过关联模型选择用户的朋友

时间:2015-08-28 14:24:02

标签: mysql sql ruby ruby-on-rails-3 activerecord

我的问题是:对于给定的用户,可以使用哪个SQL命令进行选择 确认相关关系和给定类型的所有关联启动器/启动器?

Ruby如下:

class User < ActiveRecord::Base
  has_many :relations
end

class Relation < ActiveRecord::Base
  belongs_to :initiator, class_name: "User"
  belongs_to :initiatee, class_name: "User"
end

class CreateRelations < ActiveRecord::Migration
  def change
    create_table    :relations do |t|
      t.references  :initiator
      t.references  :initiatee
      t.boolean     :is_confirmed, default: false
      t.integer     :type
    end
  end
end

1 个答案:

答案 0 :(得分:1)

你会遇到麻烦,因为Rails希望将type用于Single Table Inheritance。您还需要告诉Rails relations上的ID不是user_id,这将是has_many的默认值。由于您有两个关系方向,因此您需要同时声明两者。

  has_many :outgoing_relations, class_name: 'Relation', foreign_key: 'initiator_id'
  has_many :incoming_relations, class_name: 'Relation', foreign_key: 'initiatee_id'

从那里开始,最简单的方法是编写一个聚合其他用户的方法:

def friends(params = {})
  outgoing_relations.where(params).includes(:initiatee).map(&:initiatee) +
  incoming_relations.where(params).includes(:initiator).map(&:initiator)
end
> User.first.friends(is_confirmed: true, kind: 0)
=> [#<User id: 2, created_at: "2015-08-28 15:11:12", updated_at: "2015-08-28 15:11:12">]

在直接SQL中,您可以轻松UNION几个查询来提取您想要的其他用户ID,然后随意执行。

SELECT initiatee_id AS id
FROM relations
WHERE initiator_id = 2
  AND kind = 0
  AND is_confirmed
UNION
SELECT initiator_id AS id
FROM relations
WHERE initiatee_id = 2
  AND kind = 0
  AND is_confirmed
;
 id
----
  1
  3

这是我正在运行的数据:

SELECT * FROM users;
 id |         created_at         |         updated_at
----+----------------------------+----------------------------
  1 | 2015-08-28 15:11:10.631187 | 2015-08-28 15:11:10.631187
  2 | 2015-08-28 15:11:12.911575 | 2015-08-28 15:11:12.911575
  3 | 2015-08-28 15:14:27.762946 | 2015-08-28 15:14:27.762946

SELECT * FROM relations;
 id | initiator_id | initiatee_id | is_confirmed | kind
----+--------------+--------------+--------------+------
  1 |            1 |            2 | t            |    0
  2 |            3 |            2 | t            |    0