搜索多个列 - Rails

Posted

技术标签:

【中文标题】搜索多个列 - Rails【英文标题】:Search multiple columns - Rails 【发布时间】:2012-03-11 21:36:56 【问题描述】:

我目前正在为我的 Rails 应用程序编写一个搜索方法,目前它工作正常。我的 game.rb 中有以下内容:

def self.search(search)
  if search
    find(:all, :conditions => ['game_name LIKE ? OR genre LIKE ? OR console LIKE ?', "%#search%", "#search", "#search"])
  else
    find(:all)
  end
end

现在搜索很好,但我的问题是,如果在 game_name 中有一条包含单词“playstation”的记录,它将在那里完成搜索。它只返回该记录,而不是所有在控制台中存储“playstation”的游戏。现在我明白这是因为我的条件中有“或”,但我不知道其他选择。 'AND' 要求所有条件都匹配,否则根本不返回。我可以使用 AND 和 OR 的替代方法是什么?帮助将不胜感激。

如果有一个解决方案具有单独的搜索框和条目,那很好,我不一定要求搜索基于一个搜索表单找到所有内容。

【问题讨论】:

对你来说可能是一个解决方案,就是将 gem 用于你想要的东西,比如 github.com/ernie/meta_where 【参考方案1】:

在模型的所有字段中搜索的更通用的解决方案是这样的

def search_in_all_fields model, text
  model.where(
    model.column_names
      .map |field| "#field like '%#text%'" 
      .join(" or ")
  )
end

或者更好地作为模型本身的作用域

class Model < ActiveRecord::Base
  scope :search_in_all_fields, ->(text)
    where(
      column_names
        .map |field| "#field like '%#text%'" 
        .join(" or ")
    )
  
end

你只需要这样称呼它

Model.search_in_all_fields "test"

在你开始之前..,不,sql 注入在这里可能行不通,但仍然更好更短

class Model < ActiveRecord::Base
  scope :search_all_fields, ->(text)
    where("#column_names.join(' || ') like ?", "%#text%")
  
end

【讨论】:

【参考方案2】:

如果您想像我一样搜索列数组,我认为这是一个更有效的解决方案。

首先,最重要的是,您可以在模型中添加一个私有函数来创建查询模板:

def self.multiple_columns_like_query(array)
  array.reduce('')  |memo, x|  #
    unless memo == ''           #
      memo += ' or '            #  This is the
    end                         #  
    memo += "#x like :q"      #  core part
                               #
end                             

您可以在搜索功能中使用该功能:

def self.search(query)
  if fields = self.searched_fields && query
    where multiple_like_query(fields), q: "%#query%"
  end
end

在这里您还应该将self.searched_fields 定义为字段名称数组。

【讨论】:

【参考方案3】:

我认为这是一个更清洁的解决方案。这使您可以更轻松地添加/删除列。

key = "%#search%"
columns = %wgame_name genre console
@items = Item.where(
  columns
    .map |c| "#c like :search" 
    .join(' OR '),
  search: key
)

【讨论】:

相同的答案,但这个肯定读起来更好。不过性能会受到影响,不是吗?在所有答案中,它将一个键与多个列进行比较,您必须查看的列越多,所需的时间就越长。没有更好的办法吗? @Breno - 我能想到的唯一其他方法是连接所有字段,然后搜索该新字段。 fields = :name, :address_1, :address_2 Item.where("concat_ws(' ', #fields.join(',')) LIKE ?", "%#key%")【参考方案4】:

如果我正确理解了您的问题,那么您的 SQL 对我来说看起来不错。 OR 子句将返回在 column1、column2 或 column3 中匹配的所有记录。它不会在第一场比赛中停止。我确实看到您的参数存在问题,第一个您将 LIKE 与 % 一起使用,但在后两个您不是,也许这就是您的问题所在。

这应该是你的发现吗(第二次和第三次搜索的百分比)?

find(:all, :conditions => ['game_name LIKE ? OR genre LIKE ? OR console LIKE ?', "%#search%", "%#search%", "%#search%"])

或更好地使用 DRY 版本(以上不适用于 Rails 4.2+):

Item.where('game_name LIKE :search OR genre LIKE :search OR console LIKE :search', search: "%#search%")

【讨论】:

非常感谢 Jeff,我将 % 放在第二次和第三次搜索中,它运行良好,甚至没有注意到丢失。为所有帮助干杯。 @items = Item.where('game_name LIKE :search OR 类型 LIKE :search OR console LIKE :search', search: "%#search%").order(:name) 【参考方案5】:

如果您有 15 列要搜索,那么您将重复键 15 次。您可以这样写,而不是在查询中重复键 15 次:

key = "%#search%"

@items = Item.where('game_name LIKE :search OR genre LIKE :search OR console LIKE :search', search: key).order(:name)

它会给你同样的结果。

谢谢

【讨论】:

以上是关于搜索多个列 - Rails的主要内容,如果未能解决你的问题,请参考以下文章

Rails 虚拟属性搜索或 sql 组合列搜索

Rails 加密的列仍然允许搜索

Ruby on Rails:搜索表单 - 多个搜索字段

Rails 跨多个模型搜索

搜索多个字段 rails 5

Rails ActiveRecord - 搜索多个属性