【问题标题】:Rails 4 Conversation Model JOIN Table with conditionRails 4对话模型JOIN表与条件
【发布时间】:2015-12-17 19:04:25
【问题描述】:

我有一个与

对话模型
recipient_id
sender_id

获取当前用户的对话看起来像

conversations = Conversation.where("conversations.sender_id =? OR conversations.recipient_id =?",current_user.id,current_user.id)

让我们调用 other_user 对话中不是 current_user 的用户。

由于当前用户既可以是发件人也可以是收件人,因此无法在 users 表上使用 JOIN 或 Include 来获取对话中涉及的“其他用户”。因此,呈现对话会产生 N+1 的情况,为每个其他用户发出 1 个查询。

有没有办法使用 include 或 JOIN 获取 other_user,条件基本上是:

if current_user_id == recipient_id JOIN on recipient_id
if current_user_id == sender_id JOIN on sender_id

【问题讨论】:

    标签: ruby-on-rails postgresql ruby-on-rails-4 join


    【解决方案1】:

    如果您只需要 other_user 的某些属性,例如用户名,那么这样的东西应该可以工作:

    conversations = Conversation.find_by_sql([<<-SQL, current_user.id, current_user.id, current_user.id])
      SELECT
        convos_involving_user.*
      FROM
        -- We'll use UNION to create a table that joins together the users and
        -- conversations tables based on both sender and recipient. Each
        -- conversation will be represented by two rows in this joined table:
        -- one row joining that conversation to the sender's user info, another
        -- row joining that conversation to the recipient's user info.
        (
        -- join conversations and users based on sender
        SELECT
          conversations.*, users.id AS user_id, users.username AS other_user
        FROM
          conversations
        INNER JOIN
          users ON users.id = conversations.sender_id
        UNION
        -- join conversations and users based on recipient
        SELECT
          conversations.*, users.id AS user_id, users.username AS other_user
        FROM
          conversations
        INNER JOIN
          users ON users.id = conversations.recipient_id
        ) AS convos_involving_user
      -- Now that we conceptually have that big join table with two rows for
      -- each conversation, we filter that table. First, we are only interested
      -- in the conversations where either the recipient or sender is the
      -- current user. But we still have duplicate rows for each message, so we
      -- also filter out the rows that join a conversation rows to the
      -- current_user's row. This leaves, for each conversation involving the
      -- current user, the row that links the conversation to the other user.
      WHERE
        (recipient_id = ? OR sender_id = ?) AND user_id != ?
    SQL
    

    然后每个conversations 都会有一个other_user 方法,您可以调用它来获取其他用户的用户名。您可以在您的视图中使用它或其他。为了说明使用other_user 方法:

    conversations.each { |convo| puts convo.other_user }
    

    希望这会有所帮助。

    【讨论】:

    • 非常有趣和有帮助,我仍然需要改进我的 SQL,以便您的 cmets 在急需的地方。由于我使用分页获取对话(每批 10 个),与 1 + 10 个请求相比,该大连接的执行情况如何?我尝试在控制台中运行它,这似乎很慢......但仍在测试它。
    • 在我的机器上,在 Rails 控制台中,数据库设置有 10,000 个用户和 100,000 条随机消息,第一次运行此查询大约需要 20 毫秒,运行查询大约需要 3 毫秒随后的时间,即使对于不同的用户,大概是由于某种缓存。对我来说,这似乎是完全足够的表现。确保在 recipient_idsender_id 上有索引。这是我使用的基准gist.github.com/davidrunger/4e726ea780ad1830d4f7
    猜你喜欢
    • 2013-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-01
    • 1970-01-01
    相关资源
    最近更新 更多