2014-04-23 5 views
0

내 응용 프로그램에 대한 쿼리를 쓰려고합니다. 제목 또는 소유자 사용자 이름이 주어진 문자열 인 모든 기사를 가져오고 싶습니다 (필자의 메서드 params [: word]에 보냄). 그 결과로 주문해야 다음 CURRENT_USER의고급 검색 [rails 4]

  1. 먼저 기사

  2. CURRENT_USER 마지막으로 다른 사용자의 기사를

  3. 투표 만 대중 한 기사 하나

내 데이터베이스 모양 :

enter image description here

사용자는 다수 표를 얻었습니다.

하나의 기사는 사용자에 속하며 다수 표를 얻습니다. 그리고 기사 소유자는 투표를 할 수 없습니다.

투표는 기사와 사용자에게 연결되어야합니다.

내 솔루션은 내 자신의 기사를 얻었고, 나중에 내가 투표 한 기사, 다른 공개 기사를 얻습니다. 3 가지 쿼리를 사용하여 동일한 배열에 추가하면 3 번째 쿼리에서 반복되는 기사를 얻을 수 있습니다. 거기에 다른 해결책이 있습니까? 어쩌면 하나의 쿼리 만 사용하면 수천 개의 레코드가 또 다른 문제가됩니다.

도움을 주신 분께 감사드립니다. 고마워요 !!

답변

1

현재 사용자와 일치하거나 현재 사용자의 투표가있는 기사를 필터링하여 3 번째 쿼리에서 중복 기사를 확실히 피할 수 있습니다.

더 이상적으로 당신이 당신의 주문 요구 사항을 캡슐화하는 단일 쿼리를 수행 할, 당신이 말하는대로,

q = Article.where(article_type: 'public') 

# Filter out articles owned by the current user 
q = q.where.not(user_id: current_user.id) 

# Filter out articles voted on by the current user 
# This left joins the votes table to include the single row that will have 
# recorded the vote for the current user on the article in question 
# if the id of that left joined table is null then we know there 
# is no vote on the article for the current user and that it won't have 
# been included in the second step 
q = q.joins("left join votes on article_id = articles.id and user_id = #{User.sanitize(current_user.id)}" 
q = q.where(votes: { id: nil }) 

articles = q # or q.limit(10) or somesuch 

을하거나 할 수는 Article.where(article_type: 'public')을하고있는 가정. 얼마나 효과적 일지 확신하지 못하기 때문에 시도해 볼 필요가 있습니다. 단일 쿼리를 사용하면 기사를 매기기 쉬워집니다. (복잡한 검색 명령이 실제로 사용자에게 명확한 지 여부와 3 가지 검색을 통해 더 잘 수행 될지 여부를 고려할 수도 있습니다.하지만 이는 또 다른 질문입니다.)

이렇게하려면 약간 더 복잡한 쿼리가 필요하고 좀 더 복잡한 순서가 필요합니다. 나는 당신의 기준에 따라 순서를 설정하는 CASE을 사용하고 있습니다 :

q = Article.where("user_id = ? or article_type = 'public'", current_user.id) 

# As in the query above, join in the vote row for the current user on the article 
q = q.joins("left join votes on article_id = articles.id and user_id = #{User.sanitize(current_user.id)}" 
q = q.where(votes: { id: nil }) 

# First order by whether the user is the current user or not 
q = q.order("case when articles.user_id = #{User.sanitize(current_user.id)} then 1 else 2 end") 

# Next order by whether the user has voted or not 
q = q.order("case when votes.id is not null then 1 else 2 end") 

articles = q # or q.limit(100) or q.page(1) or somesuch 

순서 절에서 case 문으로 조건을 변환 중 1 또는 2 그래서 첫 번째 순서 절에서 예를 들어. 기사의 사용자 ID가 현재 사용자와 일치하면 1이 정렬에 사용되고 그렇지 않으면 2이 사용됩니다. 따라서 사용자의 기사는 기사 목록에서 더 높게 나타납니다. 정렬 기준은 사용자가 기사에 투표했는지 여부입니다. 그래서 그것은 order by 1, 1과 같은 것으로 끝납니다.

원하는대로해야합니다 (테스트하지는 않았으므로 여기 저기 팅겨보고 필요할 수도 있음).

+0

답변 해 주신 Shadwell에게 감사드립니다. 나는 약간 혼란 스럽다. "그 다음에 1 다른 2 끝"은 무엇을합니까? q.where (votes : {id : nil})? 나는 또한 매개 변수를 보내고있다 : 소유자의 사용자 이름과 기사 제목으로 기사를 검색하는 단어. – Moh

+0

'order (...)'에 대소 문자를 설명하는 비트를 추가했습니다. 'votes : {id : nil}'은'votes.id is null'처럼 SQL로 변환됩니다. – Shadwell