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.
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.
Maybe something like this could work:
incorrect_topics = Comment.where('sender_id <> ?', user_id).topics
Let me know if helps you anyway.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.