【问题标题】:Search In a column which stores an array在存储数组的列中搜索
【发布时间】:2017-09-04 07:49:01
【问题描述】:

在我的表 professional_infos 表中有一个列 primary_skill_ids 存储特定用户的一系列技能。我想列出所有具有某些特定技能的用户。 示例 -

user1 has primary_skill as ["1","3","5","9","4"]
user2 has primary_skill as ["1","7","9","4"]
user3 has primary_skill as ["1","4","11"]
user3 has primary_skill as ["7","9","4"]
user4 has primary_skill as ["1","7","9"]
user5 has primary_skill as ["7","9"]

现在我想执行一个搜索,比如让我所有拥有任何或所有技能 primary_skill_ids 的用户为 ["1","4]

请帮我写一个 Rails 查询。

我做了如下的事情

     wildcard_search = "%#{params[:search_title]}%"
            # key skills and best in search
      @key_skills=[] 
     @key_skills.each do | sk |
     # here I am thinking of looping through the ids and do a where clause on column primary_skill_ids but dont know its good idea


            end

【问题讨论】:

  • 您应该改用many-to-many relationship
  • 我正在做一个搜索功能。我已经定义了专业信息和技能之间的关联
  • 你能展示你的模型和/或数据库架构吗? “存储技能数组的一列primary_skill_ids”听起来更像是一个序列化的字符串而不是一个关联。
  • 这就是为什么我说“你应该改用多对多关系”。如果您在应用程序中处理数据,则序列化列很好。它们不打算通过 SQL 处理。
  • “我不能回去” – 为什么不呢?编写迁移和调整代码可能需要一些时间,但肯定会有所回报。

标签: mysql sql ruby-on-rails ruby ruby-on-rails-4


【解决方案1】:

在字符串列中序列化关系数据违反了关系数据库的理念——即你有指向其他表的外键列。在数据库中使用数组* 或字符串类型进行关联是一个非常糟糕的主意:

  • 与包含整数或 uiid 的索引列相比,搜索字符串的效率非常低。
  • 外键约束不强制执行参照完整性。
  • 这不是 ActiveRecord 的工作方式 - 这意味着您将浪费时间与框架作斗争。

相反,您想创建一个many-to-many association through a join table

class User < ApplicationRecord
  has_many :user_skills
  has_many :skills, through: :user_skills
end

class Skill < ApplicationRecord
  has_many :user_skills
  has_many :users, through: :user_skills
end

class UserSkill < ApplicationRecord
  belongs_to :user
  belongs_to :skill
end

在本例中,我们使用名为 user_skills 的表来连接两个模型:

create_table "user_skills", force: :cascade do |t|
  t.integer  "user_id"
  t.integer  "skill_id"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
  t.index ["skill_id"], name: "index_user_skills_on_skill_id", using: :btree
  t.index ["user_id"], name: "index_user_skills_on_user_id", using: :btree
end

然后您可以使用集合助手设置 UI 控件:

# app/views/users/_form.html.erb
<%= form_for(@user) do |f| %>
  <%= f.collection_check_boxes :skill_ids, Skill.all, :id, :name %>
<% end %>

# app/controllers/users_controller.rb
class UsersController < ApplicationController
  # POST /users
  def create
    @user = User.new(user_params)
    if @user.save
      redirect_to @user
    else
      render :new
    end
  end

  # PUT|PATCH /users/:id
  def update
    @user = User.find(params[:id])
    if @user.update(user_params)
      redirect_to @user
    else
      render :edit
    end
  end

  def user_params 
    params.require(:user)
          .permit(skill_ids: [])
  end
end

【讨论】:

  • 您必须创建一个迁移或 rake 任务,该任务遍历现有记录并拆分字符串并为每个记录创建一个连接表行。如果您需要有关该任务的帮助,请将其作为一个单独的问题提出,并确保包括架构和任何相关信息。
【解决方案2】:

PostgreSQL 支持标准 SQL 数组和标准 any 操作语法:

所以,你可以使用类似的 SQL

where name ilike any (array['%val1%', '%val2%'])

使用 Rails 可以这样写:

User.where('primary_skill ilike any (array[?])', ["1","4"] )

其他信息:

在您的情况下,您可以使用“ILIKE”或“LIKE”,但区别在于:

  • “ILIKE”不区分大小写
  • “LIKE”区分大小写。

通配符的使用(% 来自'%val1%')详述here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-15
    • 2015-09-24
    • 1970-01-01
    • 2021-10-11
    • 2019-01-13
    • 1970-01-01
    • 2012-08-27
    相关资源
    最近更新 更多