Итак, у меня есть эти модели.Трудный запрос для поиска новых сообщений на форуме
class Forum < ActiveRecord::Base
has_ancestry
has_many :forum_topics
end
class ForumTopic < ActiveRecord::Base
belongs_to :forum
has_many :forum_topic_reads
# has a :last_post_at date column
end
class ForumTopicRead < ActiveRecord::Base
belongs_to :forum_topic
belongs_to :user
# has a :updated_at date column
end
Очень простая установка.
Теперь то, что я хочу получить, представляет собой множество форумов форумов, в которых есть непрочитанные сообщения sowhere в их поддереве. Наличие новых сообщений определяется сравнением forum_topics.last_post_at с forum_topic_reads.updated_at, где forum_topics.id = forum_topic_reads.forum_topic_id для определенного user_id или когда отсутствует запись ForumTopicRead для этой темы и пользователя.
Проблема - единственный способ, которым мне удалось заставить ее работать, - это вручную проходить через каждый форум и получать его поддерево, а затем получать все темы для поддерева и т. Д. Это приводит к тонне похожих запросов к базе данных и, следовательно, очень медленный процесс.
Я считаю, что должен быть способ ускорить его. Мне просто нужны идентификаторы форумов, у которых есть как минимум одна непрочитанная тема в их поддеревах, не нужны счетчики, не нужны сами теги.
UPDATE
Есть намек от @MrYoshiji
Этот запрос:
ForumTopic.joins(:forum_topic_reads).where('forum_topics.last_post_at > forum_topic_reads.updated_at AND forum_topic_reads.user_id = ?', user.id).pluck(:forum_id).uniq
не работает достаточно хорошо, потому что она игнорирует темы withought соответствующие topic_reads (и создавая читать для каждой темы для каждого пользователя немного над головой)
ОБНОВЛЕНИЕ 2
Итак, я, наконец, придумал путь для провозглашения. Если я бросаю все читает на тему, когда новое сообщение добавляется к нему (таким образом, обновляя :last_post_at
поле), я буду в состоянии собрать forum_ids
с этим запросом:
"SELECT distinct forum_id FROM `forum_topics` LEFT JOIN forum_topic_reads ON forum_topic_reads.forum_topic_id = forum_topics.id AND forum_topic_reads.user_id = #{user.id} GROUP BY forum_topics.id having count(forum_topic_reads.id) < 1"
Теперь единственная большая проблема Я переводил это с SQL на ActiveRecord.
Это работает? 'ForumTopic.includes (: form_topic_reads) .where ('forum_topics.last_post_at
MrYoshiji
это может получить темы, но это не приблизит меня к получению идентификаторов форума, потому что форумы - это дерево и те темы может быть несколько слоев ниже корня. – Almaron
Было бы также лучше использовать '.joins' или' .eager_load' вместо '.includes' здесь. – Almaron