Порядок групп Rails по последнему созданному пользователем сообщению или последнему созданному комментарию - PullRequest
0 голосов
/ 10 февраля 2020

У меня есть следующие отношения: обсуждение, в котором есть сообщения, которые имеет has_many, комментарии: has_many

Я пытаюсь реализовать персонализированную панель пользователя, которая заказывает последние обсуждения в зависимости от самого последнего изменения пользователя в конкретном обсуждении, так что если пользователь создает сообщение в обсуждении, это обсуждение должно быть в верхней части панели мониторинга, и если пользователь делает комментарий к какой-либо из публикаций в данном обсуждении, это обсуждение также должно теперь находиться в верхней части его панели мониторинга.

До сих пор я могу заставить их работать только по отдельности, поэтому я изо всех сил стараюсь их объединить.

Только порядок по последнему сообщению:

@discussions = Discussion.joins(:posts).where(posts: {user: current_user}).group('discussions.id').order('MAX(posts.created_at) DESC')

Только порядок по последнему комментарию :

@discussions = Discussion.joins(:comments).where(comments: {user: current_user}).group('discussions.id').order('MAX(comments.created_at) DESC')

Моя попытка объединить их, что не работает:

@discussions = Discussion.joins(:posts,:comments).where(posts: {user: current_user}).where(comments: {user: current_user}).group('discussions.id').order('MAX(posts.created_at) DESC', 'MAX(comments.created_at) DESC')

Это работает только в зависимости от того, что я пишу на .order, но оба никогда не работают ..

Любая помощь будет высоко ценится или приветствуется любой другой способ достижения цели!

Обновление:

Вид Пользователь помог мне продвинуться немного дальше, но все еще не совсем результаты, которые я ищу

@discussions = Discussion.joins(:posts,:comments).where(posts: {user: current_user}).where(comments: {user: current_user}).group('discussions.id').order('GREATEST(MAX(posts.created_at), MAX(comments.created_at)) DESC')

Проблема здесь в том, что это работает, только если в обсуждении есть и сообщение, и комментарий, но я хочу если будет создан какой-либо из них, список обсуждений следует обновить, добавив самое последнее измененное обсуждение.

1 Ответ

1 голос
/ 11 февраля 2020
query = """
SELECT discussions.*, MAX(sub2.MostRecentDate)
FROM discussions INNER JOIN (
  SELECT posts.id, posts.discussion_id,
    CASE
      WHEN sub1.MostRecentCommentDate IS NULL OR posts.updated_at >= sub1.MostRecentCommentDate THEN posts.updated_at
      ELSE sub1.MostRecentCommentDate
    END AS MostRecentDate
  FROM posts LEFT OUTER JOIN (
    SELECT comments.post_id, MAX(comments.updated_at) AS MostRecentCommentDate
    FROM comments
    WHERE comments.user_id = ?
    GROUP BY comments.post_id
  ) AS sub1
  ON sub1.post_id = posts.id AND posts.user_id = ?
) AS sub2
ON discussions.id = sub2.discussion_id
GROUP BY discussions.id
ORDER BY MAX(sub2.MostRecentDate) DESC
"""

Discussion.find_by_sql(Discussion.send(:sanitize_sql_array, [query, current_user.id, current_user.id]))

Сначала получите максимум updated_at для таблицы комментариев, сгруппированной по post_id

SELECT comments.post_id, MAX(comments.updated_at) AS MostRecentCommentDate
FROM comments
GROUP BY comments.post_id AS sub1

Result:

|post_id|MostRecentCommentDate|
|-------|---------------------|
|  ...  |        ....         |

Далее, слева объединяет таблицу posts с таблицей результатов выше и сравните sub1.MostRecentCommentDate с posts.updated_at, чтобы получить окончательный MostRecentDate

SELECT posts.id, posts.discussion_id,
  CASE
    WHEN sub1.MostRecentCommentDate IS NULL OR posts.updated_at >= sub1.MostRecentCommentDate THEN posts.updated_at
    ELSE sub1.MostRecentCommentDate
  END AS MostRecentDate
FROM posts LEFT OUTER JOIN (
...
) AS sub2

Result:

|discussion_id|MostRecentDate|
|-------------|--------------|
|     ...     |     ....     |

Наконец, объединяет таблицу обсуждений с таблицей результатов sub2.

SELECT discussions.*, MAX(sub2.MostRecentDate) 
FROM discussions 
INNER JOIN (
...
) AS sub2
ON discussions.id = sub2.discussion_id
GROUP BY discussions.id
ORDER BY MAX(sub2.MostRecentDate) DESC

Даст нам порядок обсуждений sub2.MostRecentDate

Примечание:

  1. Возвращаемое значение find_by_sql() - это массив, а не ActiveRecord_Relation .

  2. Причиной вызова sanitize_sql_array является безопасная передача параметра в необработанный запрос. Ссылка здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...