【问题标题】:advanced search query [rails 4]高级搜索查询 [rails 4]
【发布时间】:2014-06-08 09:48:35
【问题描述】:

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

  1. 先是current_user的文章

  2. 当前用户投票的文章

  3. 终于有其他用户的文章了,但只公开了一篇

我的数据库看起来像:

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

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

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

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

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

【问题讨论】:

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


    【解决方案1】:

    您当然可以通过过滤掉与您当前用户匹配或有当前用户投票的文章来避免在第三次查询中出现重复文章。

    假设你正在做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。因此,例如在第一个 order 子句中。如果文章的用户 id 与当前用户匹配,则将使用 1 进行排序,否则将使用 2。因此,用户的文章将在文章列表中显示得更高。下一个排序标准是用户是否对文章进行了投票。所以它最终会变成order by 1, 1

    这应该可以满足您的需求(尽管我尚未对其进行测试,因此您可能需要在这里或那里进行调整)。

    【讨论】:

    • 非常感谢 Shadwell 的回答。我有点困惑,“case then 1 else 2 end”是做什么的?和 q.where(votes: { id: nil })?我还发送一个参数 :word 按所有者用户名和文章标题搜索文章。
    • 我在order(...) 中添加了一些解释案例。 votes: { id: nil } 只是转换为 SQL,如 votes.id is null
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-08
    • 2015-03-02
    • 2018-10-21
    • 2015-06-09
    • 1970-01-01
    • 2018-11-05
    • 2016-03-27
    相关资源
    最近更新 更多