2013-03-23 23 views
6

Hãy cầu nguyện, chúng ta có "Chủ đề - Mối quan hệ - Danh mục".Làm cách nào để tìm hồ sơ thiếu các bản ghi liên quan trong has_many thông qua liên kết với Bản ghi Hoạt động?

Đó là, Chủ đề has_many danh mục thông qua mối quan hệ.

Tôi nghĩ rằng nó rất dễ dàng để có được những chủ đề mà với một loại

#Relationship Model 
    Topic_id: integer 
    Category_id: integer 

    @topics=Topic.joins(:relationships) 

Nhưng, không phải mọi chủ đề có một danh mục. Vậy làm cách nào để chúng tôi truy xuất chủ đề không có danh mục? Có một số trừ số truy vấn không?

Có thể có vẻ như @topics=Topic.where('id NOT IN (?)', Relationship.all) Tôi tìm thấy số điện thoại trong activerecord equivalent to SQL 'minus' nhưng không chắc chắn về giải pháp này.

+1

Bạn không thể lấy danh sách theo thứ gì đó như 'Topic.where (: categories.nil?)' –

+0

AR trả về một mảng trống khi không có gì được tìm thấy trong mối quan hệ không phải là không. – holaSenor

+0

@ tester123, cổ vũ cho việc làm rõ, tôi đã sử dụng Datamapper trong một thời gian. –

Trả lời

10

Sẽ tốt hơn là một mối quan hệ thực sự. Nghĩ rằng đây sẽ làm việc:

@topics = Topic.joins('left join relationships on relationships.topic_id = topics.id').where('relationships.category_id is null') 

Hoặc này:

@topics = Topic 
    .joins('left join relationships on relationships.topic_id = topics.id join categories on categories.id = relationships.category_id') 
    .group('topics.id').having('count(categories.id) = 0') 
+0

bingo, câu trả lời đúng là sử dụng kết nối trái –

0

Hãy thử điều này, nó chỉ chọn Chủ đề mà đối tượng Danh mục quan hệ có độ dài bằng không.

@topics = Topic.all.select {|t| t.categories.length == 0 } 
+0

Câu trả lời MrTheWalrus có lẽ tốt hơn, tùy thuộc vào số lượng chủ đề trong bảng của bạn ngay bây giờ và tăng trưởng dự kiến ​​có thể không quan trọng, nếu điều này chỉ cần thực hiện một số kiểm tra đặc biệt, nhưng nếu điều này được gọi thường thì bạn nên đánh giá tất cả 3 tùy chọn và chọn một tùy chọn sử dụng cơ sở dữ liệu hiệu quả nhất. – holaSenor

+2

Đây là một giải pháp tồi. Nó sẽ kéo tất cả các chủ đề vào bộ nhớ và truy vấn cơ sở dữ liệu riêng biệt cho mỗi một. Điều này có thể được thực hiện như một truy vấn đơn, một giải pháp của la MrTheWalrus. Phần lớn thời gian, bất kỳ logic có thể được thực hiện trong cơ sở dữ liệu nên được thực hiện trong cơ sở dữ liệu. Bộ nhớ của nó nhanh hơn và nhiều bộ nhớ hơn và hiệu quả CPU. – eirikir

+1

Ouch. Vâng, Hãy tưởng tượng nếu chúng tôi có một triệu chủ đề !, Tôi sẽ đi với gợi ý @MrTheWalrus. – holaSenor

0

tôi đang tìm kiếm câu trả lời đơn giản nhất, mà tôi nghĩ là sử dụng includes.

topics = Topic.includes(:relationships).where(relationships: {id: nil})

Một cách khác, đó là chính xác hơn và giúp bạn suy nghĩ SQL là LEFT OUTER JOINS.

Topic.joins("LEFT OUTER JOINS relationships ON relationships.topic_id = topics.id") 
    .where(relationships: {id: nil}) 
Các vấn đề liên quan