搜索多个列 - 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的主要内容,如果未能解决你的问题,请参考以下文章