Эксклюзивная фильтрация по тегу - PullRequest
1 голос
/ 21 апреля 2010

Я использую рельсы 3.0 и MySql 5.1

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

Question, Tag и QuestionTag.

В теге есть столбец с именем name.

В вопросе много тегов с помощью QuestionTags и наоборот.

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

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

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

Было бы предпочтительнее решение с чистыми рельсами 3, но я неЭто также неблагоприятно для решения на чистом SQL.

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

1 Ответ

0 голосов
/ 22 апреля 2010

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

В модели тегов:

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
}

The & Tag.find_by_names(tag_names) объединяет две области действия так, что объединение на tags действительно является соединением на модели с областью действия.

[Обновить]

Мой sql-fu немного улучшился, поэтому я подумалЯ бы также предложил решение на чистом 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.Любое понимание будет оценено.

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