查找 has_many_through 中未关联的对象
Finding objects that are not associated in has_many_through
我有简单的 类 像这样:
class Book
has_many :book_categorizations
has_many :categories, through: :book_categorizations, source: :book_category
end
class BookCategorizations
belongs_to :book
belongs_to :book_category
end
class BookCategory
has_many :book_categorizations
has_many :books, through: :book_categorizations
end
我想找到没有类别的 Book
。如何使用 where
?
查询
您可以将带有 LEFT JOIN
的 scope
添加到您的模型中:
# in book.rb
scope :without_categories, lambda {
joins('LEFT JOIN book_categorizations ON books.id = book_categorizations.book_id').
where(book_categorizations: { book_category_id: nil })
}
可以这样使用:
Book.without_categories
#=> returns books without a category
工作原理:
假设你有一个 fruits
和一个 colors
table:
fruits
id | name
1 | Apple
2 | Orange
3 | Banana
colors
id | name
1 | black
2 | red
3 | yellow
和一个 colors_fruits
加入 table:
colors_fruits
color_id | fruit_id
2 | 1 # red Apple
3 | 3 # yellow Banana
由于 Rails' joins
方法生成 INNER JOIN
,所有连接只会 return 具有至少一种颜色的水果。橙色不会出现在列表中,因为它没有颜色(因此无法加入):
Fruit.joins(:colors)
#=> red Apple, yellow Banana (simplified)
但是当我们对没有颜色的水果感兴趣时,我们就需要LEFT JOIN
。 LEFT JOIN
包括左侧 table 的所有元素 - 即使右侧 table 没有匹配(不幸的是,这种连接没有 Rails 助手):
Fruits.joins('LEFT JOIN colors_fruits ON colors_fruits.fruits_id = fruits.id')
这会生成如下结果:
id | color | fruit_id | color_id
1 | Apple | NULL | NULL
2 | Orange | 2 | 1
3 | Banana | 3 | 3
现在我们只需要排除那些没有 color_id
Fruits.joins('LEFT JOIN colors_fruits ON colors_fruits.fruits_id = fruits.id').
where(colors_fruits: { color_id: nil })
您可能想了解 SQL JOINS
. And there is this well known diagram about joins 的不同类型。
我有简单的 类 像这样:
class Book
has_many :book_categorizations
has_many :categories, through: :book_categorizations, source: :book_category
end
class BookCategorizations
belongs_to :book
belongs_to :book_category
end
class BookCategory
has_many :book_categorizations
has_many :books, through: :book_categorizations
end
我想找到没有类别的 Book
。如何使用 where
?
您可以将带有 LEFT JOIN
的 scope
添加到您的模型中:
# in book.rb
scope :without_categories, lambda {
joins('LEFT JOIN book_categorizations ON books.id = book_categorizations.book_id').
where(book_categorizations: { book_category_id: nil })
}
可以这样使用:
Book.without_categories
#=> returns books without a category
工作原理:
假设你有一个 fruits
和一个 colors
table:
fruits
id | name
1 | Apple
2 | Orange
3 | Banana
colors
id | name
1 | black
2 | red
3 | yellow
和一个 colors_fruits
加入 table:
colors_fruits
color_id | fruit_id
2 | 1 # red Apple
3 | 3 # yellow Banana
由于 Rails' joins
方法生成 INNER JOIN
,所有连接只会 return 具有至少一种颜色的水果。橙色不会出现在列表中,因为它没有颜色(因此无法加入):
Fruit.joins(:colors)
#=> red Apple, yellow Banana (simplified)
但是当我们对没有颜色的水果感兴趣时,我们就需要LEFT JOIN
。 LEFT JOIN
包括左侧 table 的所有元素 - 即使右侧 table 没有匹配(不幸的是,这种连接没有 Rails 助手):
Fruits.joins('LEFT JOIN colors_fruits ON colors_fruits.fruits_id = fruits.id')
这会生成如下结果:
id | color | fruit_id | color_id
1 | Apple | NULL | NULL
2 | Orange | 2 | 1
3 | Banana | 3 | 3
现在我们只需要排除那些没有 color_id
Fruits.joins('LEFT JOIN colors_fruits ON colors_fruits.fruits_id = fruits.id').
where(colors_fruits: { color_id: nil })
您可能想了解 SQL JOINS
. And there is this well known diagram about joins 的不同类型。