簡體   English   中英

鏈接has_many:through關聯中的where子句(Rails 4.1.0.rc1)

[英]Chained where clauses on has_many :through association (Rails 4.1.0.rc1)

背景:我在邊緣Rails(4.1.0.rc1)上。 用戶通過CommunityUser模型擁有許多社區。 以下用戶屬於各個社區:

USERS TABLE
ID | COMMUNITY_IDS
---|--------------
1  | [2, 7, 8]
2  | [3, 4, 8]
3  | [4, 5, 7]
4  | [3, 5, 7]
5  | [3, 8, 10]
6  | [4, 6, 7]
7  | [1, 8, 10]
8  | [3, 8, 10]
9  | [2, 9, 10]
10 | [3, 6, 10]

User.joins(:communities).where(社區:{id:[5,7]})。uniq

返回與社區5或社區7相關的所有用戶:

SQL => SELECT DISTINCT“ users”。*從“ users” INNER JOIN“ community_users” ON“ community_users”。“ user_id” =“ users”。“ id” INNER JOIN“ communities” ON“ communities”。“ id” =“ community_users“。” community_id“在” communities“。” id“ IN(5,7)

ID | COMMUNITY_IDS
---|--------------
1  | [2, 7, 8]
3  | [4, 5, 7]
4  | [3, 5, 7]
6  | [4, 6, 7]

嘗試通過添加另一個where子句返回空的ActiveRecord :: Relation來進一步過濾它們(以從也與社區6相關聯的組中返回它們):

User.joins(:communities).where(社區:{id:[5,7]})。where(社區:{id:[6]})。uniq

=> SQL:SELECT DISTINCT“ users”。*從“ users” INNER JOIN“ community_users” ON“ community_users”。“ user_id” =“ users”。“ id” INNER JOIN“ communities” ON“ communities”。“ id” = “ community_users”。“ community_id”其中“ communities”。“ id” IN(5,7)和“ communities”。“ id” IN(6)

=> #<ActiveRecord::Relation []>

目標:這是此查詢的正確行為嗎? 如果是這樣,我將如何編寫此查詢以返回與EITHER社區5或社區7 AND以及社區6關聯的用戶。

問題是您在上面顯示的方式中考慮了community_ids。

ID | COMMUNITY_IDS
---|--------------
1  | [2, 7, 8]
3  | [4, 5, 7]
4  | [3, 5, 7]
6  | [4, 6, 7]

實際上,您將獲得以下中間結果集:

UID| COMMUNITY_ID
---|--------------
3  | 5
4  | 5
1  | 7
3  | 7
4  | 7
6  | 7

然后您說:好的,AND(communities)。“ id” IN(6)! 結果集中沒有具有此類ID的社區。

要使用戶擁有社區[5,7]:

users = Community.where(id:[5,7]).map(&:users).flatten.uniq

要按ID = 7的社區過濾用戶:

filtered = users.select{|u| u.communities.map(&:id).include?(6) }

這段代碼是可行的(它返回ID為6的單用戶數組),但這不是最佳解決方案。

此解決方案要求您自己編寫聯接查詢,而不是使用Ruby。 另一方面,這只是一個(快速)SQL查詢,如果您對社區進行大量比較,它將更好地擴展。

正如Vitalyp指出的那樣,CommunityUsers表看起來像這樣

CommunityUsers
user_id | community_id
--------|--------------
 1      | 5
 2      | 5
 1      | 7
 2      | 7
 1      | 6
 3      | 6

為了找到包含社區5或7以及社區6的記錄,我們可以選擇兩者並加入它們。

User.joins('INNER JOIN "community_users" c1 ON c1."user_id" = "users"."id" AND c1."id" IN [5, 7]')
    .joins('INNER JOIN "community_users" c2 ON c2."user_id" = "users"."id" AND c2."id" = 6')

使用內部聯接,查詢僅選擇社區5或7(第一聯接子句) 社區6(第二聯接子句)中的那些用戶。


附加提示:在community_users.user_id上創建索引也會加快查詢速度。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM