高级搜索查询[rails 4]

时间:2014-04-23 13:48:37

标签: ruby-on-rails sqlite ruby-on-rails-4 database-schema

我正在尝试为我的应用程序编写查询。我想得到所有标题或所有者用户名是给定字符串的文章(我发送给我的方法params [:word])。结果应按以下顺序排序:

  1. 首先是current_user的文章

  2. current_user投票的文章

  3. 最后是其他用户的文章,但只公开一个

  4. 我的数据库看起来像:

    enter image description here

    用户有很多文章,票数很多。

    一篇文章属于一个用户,有很多票。文章所有者不能投票。

    投票应与文章和用户相关联。

    我的解决方案是获取我自己的文章,后来我投票的文章,然后是其他公开文章。所有这一切,使用3个不同的查询并将它们附加到同一个数组,但是,也许我会在第3个查询中得到一些重复的文章。那还有其他解决方案吗?可能只使用一个查询,有数千个记录应该是另一个问题。

    非常感谢任何帮助!非常感谢!!

1 个答案:

答案 0 :(得分:1)

通过过滤掉与当前用户匹配的文章或者当前用户投票的文章,您当然可以避免第3次查询中的重复文章。

假设你正在做Article.where(article_type: 'public'),你可以做

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

或者,正如您所说,理想情况下,您希望执行一个封装订购要求的查询。我不确定会有多高效,所以你可能需要尝试一下。通过单个查询,可以更轻松地对文章进行分页。 (您可能还想考虑一个复杂的搜索顺序是否真的对您的用户清楚,以及您是否会更好地使用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

order子句中的case语句将条件转换为1或2.因此,例如在first order子句中。如果文章的用户ID与当前用户匹配,则1将用于排序,否则将使用2。因此,用户的文章将在文章列表中显得更高。下一个要排序的标准是用户是否对该文章进行了投票。所以它最终会像order by 1, 1

那应该做你想要的(虽然我没有测试过,所以你可能需要在这里或那里进行调整)。

相关问题