Reputation: 459
For example I have 2 tables: topics and comments.
topic has_many comments. comment belongs_to topic.
Comments table have column sender_id where I save user's id, who create this comment.
Task: Select ids of topics, which is not commented by this user (I know user_id). (I want to do it with one query).
Earlier I do it so. ( two queries ) ( My database - PostgreSQL)
incorrect_topics = Comment.select(:topic_id).where(:sender_id => user_id).map { |elem| elem.topic_id }
ids = select(:id).where(["id NOT IN (?)", incorrect_topics]).map { |elem| elem.id }
It works fine, but I suppose that if app become bigger it will be serious problem.
Thanks.
Upvotes: 0
Views: 107
Reputation: 434665
If all you need are the IDs then you could bypass all the ActiveRecord stuff and do it by hand:
ids = connection.select_rows(%Q{
select id
from topics
where id not in (
select topic_id
from comments
where sender_id = #{user_id.to_i}
)
}).map { |r| r.first.to_i }
If you're certain the user_id
is already an integer then you don't need the .to_i
. You could also use #{connection.quote(user_id)}
. You could also use the same SQL with select_values
if you wanted to avoid unwrapping he rows by hand with a map
.
If you wanted the Topic instances then find_by_sql
would be an option:
topics = find_by_sql(%q{
select *
from topics
where id not in (
select topic_id
from comments
where sender_id = :user_id
)
}, :user_id => user_id)
Some things are clearer when you use straight SQL than when you try to wrap it up in ActiveRecord stuff.
Upvotes: 1
Reputation: 8240
Maybe something like this could work:
incorrect_topics = Comment.where('sender_id <> ?', user_id).topics
Let me know if helps you anyway.
Upvotes: 0