I am doing a query over my POSTGRESQL DB. My app has Articles and the Articles can have a number of Hashtags. Those relations are saved in a joined table of Hashtags and Articles.
I have a working method which gives me back Articles which have certain hashtags, or gives me back all articles who do not contain certain hashtags
def test(hashtags, include = true)
articles= []
hashtags.split(' ').each do |h|
articles+= Article.joins(:hashtags).where('LOWER(hashtags.value) LIKE LOWER(?)', "#{h}")
end
if include
articles.uniq
else
(Article.all.to_set - articles.uniq.to_set).to_a
end
end
I could call it like this:
test("politics people china", true)
And it would give me all Articles who have one of those hashtags related to
Or I could call it like that
test("politics people china", false)
And it would give me all Articles EXCEPT those who have one of these hashtags
It works well, but I dont think this is very efficient as I do so much in Ruby and not on DB level.
I tried this:
def test2(hashtags, include = true)
articles= []
pattern = ''
hashtags.split(' ').each do |h|
pattern += "#{h}|"
end
pattern = '(' + pattern[0...-1] + ')'
if include
articles = Article.joins(:hashtags).where('hashtags.value ~* ?', "#{pattern}")
else
articles = Article.joins(:hashtags).where('hashtags.value !~* ?', "#{pattern}")
end
articles.uniq
end
But it does not behave like I thought it would. First of all if I call it like that:
test2("politics china", true)
It wouldn't only give me all Articles who have a hashtags politics or china, but also all artcles who have a hashtag containing one of the letters in politics or china like so:
(p|o|l|i|t|c|s|h|n|a)
but it should check for this actually, and the pattern looks actually like this, what I can see in the console:
(politics|china)
which it doesnt what I find is strange tbh...
And with
test2("politics", false)
It only gives me articles who have one or more hashtags associated to, BUT leaves out the ones who have no hashtag at all
Can someone help me make my working method more efficient?
EDIT: Here is my updated code like suggested in an answer
def test2(hashtags, include = false)
hashtags =
if include
Hashtag.where("LOWER(value) iLIKE ANY ( array[?] )", hashtags)
else
Hashtag.where("LOWER(value) NOT iLIKE ANY ( array[?] )", hashtags)
end
Slot.joins(:hashtags).merge(hashtags).distinct
end
It still lacks to give me Articles who have NO hashtags at all if incude is false unfortunately