2015-08-19 5 views
2

Итак, у меня есть эти модели.Трудный запрос для поиска новых сообщений на форуме

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.

+0

Это работает? 'ForumTopic.includes (: form_topic_reads) .where ('forum_topics.last_post_at MrYoshiji

+0

это может получить темы, но это не приблизит меня к получению идентификаторов форума, потому что форумы - это дерево и те темы может быть несколько слоев ниже корня. – Almaron

+0

Было бы также лучше использовать '.joins' или' .eager_load' вместо '.includes' здесь. – Almaron

ответ

0
ForumTopic.unscoped.joins(:forum_topic_reads).where('user_id = ?', user[:id]).group(:id).having('forum_topic_reads.count < 1').pluck(:forum_id) 
+0

emm..where сделал это 'view_mappings.count'? – Almaron

+0

@Almaron Извините, что ответ был базой некоторых из моего существующего кода. (copy paste) –

+1

, но как этот запрос проверяет разницу во времени между прочитанным и последним темой тем? – Almaron

Смежные вопросы