如何编写迁移以将 JSON 字段转换为 Postgres 数组以在 rails 中查询?
How to write a migration to convert JSON field to Postgres Array for querying in rails?
有一个旧的 table,列类型为 JSON,但此列中仅存储数组。
即使我正在存储数组,我也无法使用 ANY
关键字查询此字段(它将在 Postgres 中的数组类型列上工作,如 post)
例如:假设['Apple'、'Orange'、'Banana']在[=中存储为Json 13=] 列,我想像 Market.where(":name = ANY(fruits)", name: "Orange")
一样查询并获取所有有 Oranges 的市场。
任何人都可以帮我写一个迁移来将现有列(类型: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
UPDATE 将 JSON 数组转换为 Postgres 数组的方法:
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 数组的要求。
查找 json
字段中具有 'Orange' 的行的更简单方法:
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
有一个旧的 table,列类型为 JSON,但此列中仅存储数组。
即使我正在存储数组,我也无法使用 ANY
关键字查询此字段(它将在 Postgres 中的数组类型列上工作,如 post)
例如:假设['Apple'、'Orange'、'Banana']在[=中存储为Json 13=] 列,我想像 Market.where(":name = ANY(fruits)", name: "Orange")
一样查询并获取所有有 Oranges 的市场。
任何人都可以帮我写一个迁移来将现有列(类型: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
UPDATE 将 JSON 数组转换为 Postgres 数组的方法:
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 数组的要求。
查找 json
字段中具有 'Orange' 的行的更简单方法:
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