多 table、多过滤器 postgresql 搜索 - rails
multi-table, mult-filters postgresql search - rails
在浏览了包括 pg_search 在内的几个选项后,我很难找到可以帮助我了解如何将多table、多过滤器搜索放在一起的资源。我有两个模型,profile 和 subject,它们都通过 unique_id 关联。我想做的是让用户 select 来自许多过滤器,跨越许多模型,并 return 结果。例如,我希望用户能够从个人资料模型中搜索 name 属性,并从主题模型中搜索 grade 属性,并且return 属于这些搜索参数的列表。我在创建一个搜索过滤器时没有问题,但是当我为不同的类别添加更多过滤器时,其他搜索过滤器似乎没有相互通信。下面是我的一些代码。很高兴添加更多代码,只是真的不知道该去哪里。如果您能提供任何帮助或指导,我们将不胜感激。
配置文件数据库
class CreateProfiles < ActiveRecord::Migration
def change
create_table :profiles do |t|
t.integer :unique_id
t.string :name
t.integer :age
t.string :sex
t.references :user, index: true, foreign_key: true
t.timestamps null: false
end
end
end
主题数据库
class CreateSubjects < ActiveRecord::Migration
def change
create_table :subjects do |t|
t.integer :unique_id
t.string :subject
t.integer :grade
t.references :user, index: true, foreign_key: true
t.timestamps null: false
end
end
end
个人资料模型
class Profile < ActiveRecord::Base
include PgSearch
belongs_to :user
def self.import(file)
CSV.foreach(file.path, headers: true) do |row|
attributes = row.to_hash
Profile.create! attributes
end
end
end
学科模型
class Subject < ActiveRecord::Base
include PgSearch
belongs_to :user
def self.import(file)
CSV.foreach(file.path, headers: true) do |row|
attributes = row.to_hash
Subject.create! attributes
end
end
end
先看看Rails join table queries and Rails method chaining。
让我们看一些您可能会做什么的例子。假设您要查找个人资料名称为 "John" 且主题等级为 100 的用户。您可以执行以下操作:
@users = User.where(profiles: { name: "John" }, subjects: { grade: 100 }).joins(:profiles, :subjects)
请注意,仅当您根据特定值进行过滤时,使用散列方法才有效。现在假设您要查找个人资料名称为 "John"(例如 "John"、"John Smith" 或 "John Doe")且成绩大于 85 的用户,您将执行以下操作:
@users = User.where("profiles.name ILIKE ? AND subjects.grade > ?", "John%", 85).joins(:profiles, :subjects)
ILIKE
查询适用于 Postgres,但我记得 MySQL 不适用。请注意,在这两个语句中,您都必须在查询中提及加入的 table 名称,并且还必须调用 joins
方法。
现在您知道如何加入 tables,我们现在可以看看如何使用参数和范围来过滤它。
class User
scope :by_profile_name, -> (input) do
where("profiles.name = ?", input[:profile_name]).joins(:profiles) if input[:profile_name]
end
scope :by_subject_grade, -> (input) do
where("subjects.grade = ?", input[:subject_grade].to_i).joins(:subjects) if input[:subject_grade]
end
end
然后在您的控制器中您将拥有:
@users = User.by_subject_grade(params).by_profile_name(params)
这只是一个粗略的开始,请查看上面的链接了解更多详细信息。
在浏览了包括 pg_search 在内的几个选项后,我很难找到可以帮助我了解如何将多table、多过滤器搜索放在一起的资源。我有两个模型,profile 和 subject,它们都通过 unique_id 关联。我想做的是让用户 select 来自许多过滤器,跨越许多模型,并 return 结果。例如,我希望用户能够从个人资料模型中搜索 name 属性,并从主题模型中搜索 grade 属性,并且return 属于这些搜索参数的列表。我在创建一个搜索过滤器时没有问题,但是当我为不同的类别添加更多过滤器时,其他搜索过滤器似乎没有相互通信。下面是我的一些代码。很高兴添加更多代码,只是真的不知道该去哪里。如果您能提供任何帮助或指导,我们将不胜感激。
配置文件数据库
class CreateProfiles < ActiveRecord::Migration
def change
create_table :profiles do |t|
t.integer :unique_id
t.string :name
t.integer :age
t.string :sex
t.references :user, index: true, foreign_key: true
t.timestamps null: false
end
end
end
主题数据库
class CreateSubjects < ActiveRecord::Migration
def change
create_table :subjects do |t|
t.integer :unique_id
t.string :subject
t.integer :grade
t.references :user, index: true, foreign_key: true
t.timestamps null: false
end
end
end
个人资料模型
class Profile < ActiveRecord::Base
include PgSearch
belongs_to :user
def self.import(file)
CSV.foreach(file.path, headers: true) do |row|
attributes = row.to_hash
Profile.create! attributes
end
end
end
学科模型
class Subject < ActiveRecord::Base
include PgSearch
belongs_to :user
def self.import(file)
CSV.foreach(file.path, headers: true) do |row|
attributes = row.to_hash
Subject.create! attributes
end
end
end
先看看Rails join table queries and Rails method chaining。
让我们看一些您可能会做什么的例子。假设您要查找个人资料名称为 "John" 且主题等级为 100 的用户。您可以执行以下操作:
@users = User.where(profiles: { name: "John" }, subjects: { grade: 100 }).joins(:profiles, :subjects)
请注意,仅当您根据特定值进行过滤时,使用散列方法才有效。现在假设您要查找个人资料名称为 "John"(例如 "John"、"John Smith" 或 "John Doe")且成绩大于 85 的用户,您将执行以下操作:
@users = User.where("profiles.name ILIKE ? AND subjects.grade > ?", "John%", 85).joins(:profiles, :subjects)
ILIKE
查询适用于 Postgres,但我记得 MySQL 不适用。请注意,在这两个语句中,您都必须在查询中提及加入的 table 名称,并且还必须调用 joins
方法。
现在您知道如何加入 tables,我们现在可以看看如何使用参数和范围来过滤它。
class User
scope :by_profile_name, -> (input) do
where("profiles.name = ?", input[:profile_name]).joins(:profiles) if input[:profile_name]
end
scope :by_subject_grade, -> (input) do
where("subjects.grade = ?", input[:subject_grade].to_i).joins(:subjects) if input[:subject_grade]
end
end
然后在您的控制器中您将拥有:
@users = User.by_subject_grade(params).by_profile_name(params)
这只是一个粗略的开始,请查看上面的链接了解更多详细信息。