2010-04-21 3 views
1

Я использую рельсы 3.0 и MySql 5,1Exclusive Фильтрация по тегу

У меня есть эти три модели:

вопрос, Tag и QuestionTag.

Тег имеет столбец под названием name.

Вопрос имеет много тегов через QuestionTags и наоборот.

Предположим, у меня есть n теги. Как найти только вопросы, которые имеют всеn теги, обозначенные тегом name.

И как это сделать в одном запросе.

(Если вы можете убедить меня, что делает его более чем один запрос является оптимальным, я буду открыт для этого)

чистый рельсам будет предпочтительным 3 решение, но я не прочь к чистому SQL.

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

ответ

0

Это решение, которое я нашел для себя. Немодифицированный, он будет работать только в Rails 3 (или выше).

В модели Tag:

scope :find_by_names, lambda { |names| 
    unless names.empty? 
    where("tags.name IN (#{Array.new(names.length, "?").join(",")})", *names) 
    else 
    where("false") 
    end 
} 

В модели Вопроса:

scope :tagged_with, lambda { |tag_names| 
    unless tag_names.blank? 
    joins(:question_tags). 
    where("questions.id = question_tags.question_id"). 
    joins(:tags).where("tags.id = question_tags.tag_id"). 
    group("questions.id"). 
    having("count(questions.id) = ?", tag_names.count) & Tag.find_by_names(tag_names) 
    else 
    scoped 
    end 
} 

& Tag.find_by_names(tag_names) сочетает в себе две областях таким образом, чтобы присоединиться на tags действительно присоединиться на контекстную модели.

[Update]

My SQL-фу улучшилось немного, так что я бы предложил чистое решение SQL также:

SELECT q.* 
FROM (
SELECT DISTINCT q.* 
FROM `questions` q 
JOIN question_tags qt 
ON qt.question_id = q.id 
JOIN tags t 
ON t.id = qt.tag_id 
WHERE t.name = 'dogs' 
) AS q 
JOIN question_tags qt 
ON qt.question_id = q.id 
JOIN tags t 
ON t.id = qt.tag_id 
WHERE t.name = 'cats' 

Это находит все вопросы, которые были помечены как «кошки», так и «собаки». Идея состоит в том, чтобы иметь вложенный подзапрос для каждого тега, который я хочу фильтровать.

Существует несколько других способов. Я не уверен, имеет ли смысл иметь подзапрос в предложении FROM вместо предложения WHERE. Любое понимание было бы оценено.

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