[英]Rails / Active Record has_many through association - fetching a record
[英]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.