双向自引用关联的类方法问题

时间:2011-06-09 06:39:54

标签: sql ruby-on-rails ruby-on-rails-3 bidirectional self-reference

我正在尝试创建一个应用,其中用户('current_user')评估其他两个用户('user1'和'user2')之间的兼容性。他们可以正面或负面评价兼容性:评级两个用户“兼容”创建同一类的两个资源('positive_connection'和'inverse_positive_connection' - 用于双向性),并将它们评级为“不兼容”也会创建两个资源('negative_connection' '和'inverse_negative_connection')。所以有positive_connection,negative_connection和user的模型。

每个评级资源属于创建它的用户,也属于由其连接的用户。同时拥有正面和负面评级非常重要。

这是我的问题:在每个用户(@user)页面上,我想显示单独的列表:

  1. overall_positively_connected_to(@user)(即positive_connections.count > negative_ratings.count)和

  2. 的用户
  3. overall_negatively_connected_to(@user)的用户(即negative_connections.count > positive_ratings.count)。


  4. 我似乎无法做的是编写一个方法,只抽出那些被评为“兼容”或“不兼容”的用户

    从阅读Michael Hartl的rails教程(我对这一切都是全新的),我想我需要在用户模型中编写类似的内容:

    class User < ActiveRecord::Base
    
    
    def self.that_are_compatible_with
    
         User.overall_positively_connected_to(user)
    end
    .
    .
    .
    


    修改

    从完全不了解SQL查询开始,我编写了这两个类方法来查找与@user(分别)负面和正向连接的用户:

    .
    .
    .
      def self.with_neg_connections_to(user)
       joins(:negative_connections).
       where(:negative_connections => {:user_a_id => user})
      end
    
      def self.with_pos_connections_to(user)
       joins(:positive_connections).
       where(:positive_connections => {:user_a_id => user})
      end
    


    但这没什么帮助。我需要的是一种获取用户overall_positively_connected_to(user)的方法。我认为该方法将涉及两个连接,并执行类似下面的操作:

      def self.overall_positively_connected_to(user)
        joins(:positive_connections).joins(:negative_connections).
        where((:negative_connections => {:user_a_id => user}).count > (:positive_connections => {:user_a_id => user}).count)
      end
    


    但在这里我完全陷入困境:显然不对。我无法在任何地方找到其他类似的例子......

    任何对此的任何帮助都会很棒,因为我对SQL查询没有任何线索。如果需要更多代码,请告诉我。提前谢谢!

2 个答案:

答案 0 :(得分:1)

经过几天的努力,我决定解决问题的最佳方法可能是改变模型 - 通过添加额外的“连接”模型并让用户对每个模型进行正面或负面投票连接,或通过减小到单个“连接”模型,其中每个连接的正面或负面字符用+ 1 / -1标记。

this question的答案中可以找到几种替代方案。

答案 1 :(得分:0)

如果我正确理解了这个问题,那么使这一切变得复杂的一个原因是目标用户可能位于User1或User2中。也就是说,如果我们在ID = 4的用户的所有连接之后,那么我们可以让User1 = 4或User2 = 4 ......是吗?

如果是这样,那么假设你的positive_connections和negative_connections模型/表包含如下字段:

  • ID:主键
  • ReportingUser:进行连接的用户
  • UserA:第一个连接用户
  • UserB:第二个连接用户

然后,下面(相当混乱的)SQL将为您提供每个用户的正面和负面连接的摘要:

set @user = 2;

SELECT DISTINCT
    @user TargetUser,
    u.ID as OtherUser,
    COALESCE(qryPositive.PositiveConnections, 0) as PositiveConnections,
    COALESCE(qryNegative.NegativeConnections, 0) as NegativeConnections,
    case
      when COALESCE(qryPositive.PositiveConnections, 0) > COALESCE(qryNegative.NegativeConnections, 0)
      then 'positive'
      when COALESCE(qryPositive.PositiveConnections, 0) < COALESCE(qryNegative.NegativeConnections, 0)
      then 'negative'
      else 'neutral'
    end as Status
FROM
    users u
LEFT JOIN
    (
        -- The number of positive connections between the @user and each other user
        SELECT
            @user TargetUser,
            a.OtherUser,
            COUNT(*) as PositiveConnections
        FROM
        (
            -- The positive_connections rows with our @user in it
            -- and the other user that the connection associates them with
            select -- pc.ID as pcID, pc.UserA, pc.UserB,
            case
              when pc.UserA = @user then pc.UserB
              else pc.UserA
            end as OtherUser
            from positive_connections pc
            where
            (
              -- Check both columns
              (pc.UserA = @user)
              or
              (pc.UserB = @user)
            )
        ) a
        GROUP BY
            OtherUser
    ) qryPositive
    on qryPositive.OtherUser = u.ID

LEFT JOIN
    (
        -- The number of negative connections between the @user and each other user
        SELECT
            @user TargetUser,
            b.OtherUser,
            COUNT(*) as NegativeConnections
        FROM
        (
            -- The negative_connections rows with our @user in it
            -- and the other user that the connection associates them with
            select -- pc.ID as pcID, pc.UserA, pc.UserB,
            case
              when pc.UserA = @user then pc.UserB
              else pc.UserA
            end as OtherUser
            from negative_connections pc
            where
            (
              -- Check both columns
              (pc.UserA = @user)
              or
              (pc.UserB = @user)
            )
        ) b
        GROUP BY
            OtherUser
    ) qryNegative
    on qryNegative.OtherUser = u.ID

WHERE
    u.ID <> @user

它负责SQL(我可以发布我喜欢的样本数据)。现在在rails中,将它分离到模型中的单独类方法中肯定是个好主意,就像你已经开始做的那样。

就使用rails构建查询而言,此页面是一个非常好的资源。 http://guides.rubyonrails.org/active_record_querying.html

这是你要找的东西吗?如果是这样,那么我们可以构建活动记录查询。 (我有一种感觉,虽然我可能误解了这个问题......)