繁体   English   中英

如何编写迁移以将 JSON 字段转换为 Postgres 数组以在 rails 中查询?

[英]How to write a migration to convert JSON field to Postgres Array for querying in rails?

有一个列类型为 JSON 的旧表,但只有 arrays 存储在此列中。 即使我正在存储数组,我也无法使用ANY关键字查询该字段(这将适用于 Postgres 中数组类型列,如本文中所示)

例如:假设 ['Apple', 'Orange', 'Banana'] 在fruits列中存储为 Json,我想查询Market.where(":name = ANY(fruits)", name: "Orange")并获得所有可用橙子的市场。

谁能帮我写一个迁移来将现有的列(类型:Json)更改为数组类型?

一个假设json字段的示例:

\d json_test 
               Table "public.json_test"
  Column   |  Type   | Collation | Nullable | Default 
-----------+---------+-----------+----------+---------
 id        | integer |           |          | 
 fld_json  | json    |           |          | 
 fld_jsonb | jsonb   |           |          | 
 fruits    | json    |           |          | 

insert into json_test (id, fruits) values (1, '["Apple", "Orange", "Banana"] ');
insert into json_test (id, fruits) values (2, '["Pear", "Orange", "Banana"] ');
insert into json_test (id, fruits) values (3, '["Pear", "Apple", "Banana"] ');

WITH fruits AS 
(SELECT 
    id, json_array_elements_text(fruits) fruit 
 FROM json_test) 
SELECT 
   id 
FROM 
   fruits
WHERE 
    fruit = 'Orange';
 id 
----
  1
  2

将 JSON 数组转换为 Postgres 数组的UPDATE方法:

SELECT 
    array_agg(fruit) 
FROM 
    (SELECT 
        id, json_array_elements_text(fruits)AS fruit 
    FROM 
    json_test) AS elements 
GROUP BY 
    id;

 array_agg       
-----------------------
 {Pear,Apple,Banana}
 {Pear,Orange,Banana}
 {Apple,Orange,Banana}

这假设 JSON 数组具有同质元素,因为这是 Postgres arrays 的要求。

json字段中查找具有“橙色”的行的更简单方法:

SELECT 
    id, fruits 
FROM 
    json_test 
WHERE 
    fruits::jsonb ? 'Orange';

 id |             fruits             
----+--------------------------------
  1 | ["Apple", "Orange", "Banana"] 
  2 | ["Pear", "Orange", "Banana"] 

class AddArrayFruitsToMarkets < ActiveRecord::Migration[6.0]
  def up
    rename_column :markets, :fruits, :old_fruits
    add_column :markets, :fruits, :string, array: true
    Market.update_all('fruits = json_array_elements(old_fruits)')
  end
end
class RemoveJsonFruitsFromMarkets < ActiveRecord::Migration[6.0]
  def up
    remove_column :markets, :old_fruits
  end
end

但是,如果您真的要做某事,为什么不创建表格,因为您并没有真正改进任何东西?

class Fruit < ApplicationRecord
  validates :name, presence: true
  has_many :market_fruits
  has_many :markets, through: :market_fruits
end

class MarketFruit < ApplicationRecord
  belongs_to :market
  belongs_to :fruit
end

class Market < ApplicationRecord
  has_many :market_fruits
  has_many :fruits, through: :market_fruits

  def self.with_fruit(name)
    joins(:fruits)
      .where(fruits: { name: name })
  end

  def self.with_fruits(*names)
    left_joins(:fruits)
      .group(:id)
      .where(fruits: { name: names })
      .having('COUNT(fruits.*) >= ?', names.length) 
  end
end

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM