【问题标题】:Find record through association using associations foreign keys使用关联外键通过关联查找记录
【发布时间】:2015-02-24 01:56:21
【问题描述】:

我有以下 4 个模型

 class User < ActiveRecord::Base
   has_many :conversation_memberships
   has_many :conversations, :through => :conversation_memberships  
   has_many :messages, :through => :conversations
 end

 class Conversation < ActiveRecord::Base
   has_many :messages
   has_many :members, :class_name => 'ConversationMembership', :foreign_key => :conversation_id
   has_many :users, :through => :members
 end

 class ConversationMembership < ActiveRecord::Base
   belongs_to :user
   belongs_to :conversation
 end

 class Message < ActiveRecord::Base
   belongs_to :conversation
   belongs_to :user
 end

所以Conversation 可以有多个usersConversationMembership。理想情况下,每个对话的用户集都是唯一的,因此用户1,2,3 在他们之间只能进行一次对话。

通过此设置,我可以使用以下 Rails 方法查询 Conversation 的成员 ID:

Conversation.find(1).user_ids # => [1,2,3] 

这为我提供了用户 123 之间对话中的用户 ID。

我想要做的基本上是 相反,因此请尝试查找这 3 个用户和这些用户之间的对话。伪代码形式,类似于Conversation.find_by(:user_ids =&gt; [1,2,3])

此语法具有预期的效果,但使用了 3 个(或更多)查询:

User.find(1).conversations & User.find(2).conversations & User.find(3).conversations

我希望通过单个查询(可能使用子查询)来实现这一点,但我一生都无法弄清楚如何让它工作。自从我上次不得不编写像这样复杂的原始 SQL 以来已经快 6 年了,所以我的大脑充满了蜘蛛网。

总结: 我希望能够查询 Conversation 模型并返回 2 个或更多用户之间的现有对话。

如果所有其他方法都失败了,我能想到的最接近的解决方法是将conversation.user_ids 的内容存储在Array 模型上的Array 列中。

【问题讨论】:

  • 我发现与此相关的唯一其他相关帖子在这里:stackoverflow.com/questions/18889824/… 但它并没有真正解决我的问题,因为它暗示了相同的@987654338 @ 与 &amp; 的简写,不能链接到 n 没有一些元编程的成员数

标签: ruby-on-rails postgresql activerecord arel


【解决方案1】:

你需要加入用户表:

Conversation.joins(:users).where('users.id' => [1, 2, 3])

【讨论】:

  • 您也可以在 where 调用中引用关联名称:Conversation.joins(:users).where(users: { id: [1, 2, 3] })
  • 不幸的是,我以前试过这个。这种方法的问题来自多个关联。所以让我们说c = Convo.find(1) &amp;&amp; c.user_ids == [1,2]c1 = Convo.find(2) &amp;&amp; c1.user_ids == [1,3]c2 = Convo.find(3) &amp;&amp; c2.user_ids == [1,2,3]。使用Conversation.joins(:users).where('users.id' =&gt; [1,2,3])(或@NathanWallace 方法)将返回cc1 c2 我只想要c2
  • 让我知道我是否可以更好地格式化上面的内容,也感谢你们的回复。如果您有任何提示可以帮助我更好地格式化我的初始问题,以便清楚上述评论,请告诉我
【解决方案2】:

同样的问题几乎让我多次通过窗口启动笔记本电脑,但以下似乎可行。如果有人知道更简单的方法,请说出来。

Conversation.rb

def self.findConvo(idArr)  # pass in array of user ids
  length = idArr.length
  idString = "('" + idArr.join("','") + "')"  # you have to remove the square brackets and use round ones to keep the sql happy
  @conversation = Conversation.find_by_sql("

      SELECT *
      FROM (
          SELECT cm3.conversation_id
          FROM (
              SELECT       cm1.conversation_id
              FROM         conversationmembership cm1
              WHERE        cm1.user_id IN #{idString}   /* find all conversations involving at least one of our users */
              GROUP BY     cm1.conversation_id
              HAVING       COUNT(cm1.user_id) = #{length}  /* pick out the conversations involving all our users and possibly other users */
          ) AS cm2
          INNER JOIN   conversationmembership cm3
          ON           cm2.conversation_id = cm3.conversation_id   /* get ALL users for our conversations */
          GROUP BY     cm2.conversation_id, cm3.conversation_id
          HAVING       COUNT(cm3.user_id) = #{length}   /* pick out the only conversation involving ONLY our users */
      ) AS cm4
      INNER JOIN   conversations con1
      ON           cm4.conversation_id = con1.id      /* bolt on conversations */

  ")
  return @conversation.first # because @conversation is a collection
end

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-21
    • 2016-01-11
    • 1970-01-01
    • 2012-07-29
    • 2016-03-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多