我的模型有一个如下所示的列(示例):
column = [{:A => "1", :B => "2"}, [a, b, c, ..., n]]
a
,b
,c
和n
也是哈希,如下(示例):
a = {:X => "x", :Y => "y"}
目前,如果我调用模型的记录m
,例如m.column[0][:A]
,则会返回=> "1"
如果我致电m.column[1][0]
,我会a = {:X => "x", :Y => "y"}
到目前为止,非常好。
现在的问题是,如何获得模型的所有记录的数组,例如column[0][:A] = "1"
???
我尝试这样的事情(但它不起作用):
Model.where("column[0][:A] = ?", "1")
错误说:
PG::SyntaxError: ERROR: syntax error at or near ":"
修改
column
是text
数据类型
在其模型中它有serialize :column, Array
答案 0 :(得分:1)
您的问题是您使用serialize
存储数据,serialize
只是将大量不可疑的YAML丢入数据库。在PostgreSQL中解析YAML肯定是可能的,但它会很慢而且毫无意义。
如果你真的需要存储一系列哈希值,那么PostgreSQL的jsonb
类型将是你最好的选择。您不会在数据库中获得符号键,但是您将获得字符串键,因此这个Ruby数据:
[{:A => "1", :B => "2"}, {:C => 6, :D => 11}]
看起来像这个JSON:
[ { "A": "1", "B": "2" }, { "C": 6, "D": 11 } ]
在数据库内。
在数据库中有jsonb
后,您可以使用PostgreSQL提供程序的所有JSON functions and operators查询它,您甚至可以索引JSON以支持更快的查询。在您的情况下,您的查询将如下所示:
Model.where("column->0->>'A' = ?", '1')
RHS上带有整数的->
运算符就像Ruby的Array#[]
方法一样:
->
int
获取JSON数组元素(从零开始索引,从最后开始计算负整数)
在RHS上使用字符串,它就像Ruby的Hash#[]
一样。请注意,->
返回JSON,而不是文本或整数。 ->>
运算符与->
相同,但它会返回文本,因此您最后会使用该运算符来使比较更清晰。
或者你可以说:
Model.where("column->0->'A' = ?", '1'.to_json)
将string-vs-JSON逻辑推送到Ruby中。
一旦你的数据库架构有意义(即使用PostgreSQL jsonb
而不是Rails' s serialize
),一切都很简单,但你怎么从这里到达那里?首先从模型中删除serialize :column, Array
,然后您需要执行以下三步迁移:
添加jsonb
列:
def change
add_column :models, :column_j, :jsonb
end
从数据库中读取每个column
值,手动解压缩YAML,然后手动编写JSON:
def up
connection.execute('select id, column from models').each do |row|
a = YAML.load(row['column'])
connection.raw_connection.exec(
'update models set column_j = $1 where id = $2',
[ a.to_json, row['id'].to_i ]
)
end
end
请注意,您不能将此模型用作模型类,并且数据库不再同意models
表的结构和格式。
将旧的column
替换为新的column_j
:
def change
remove_column :models, :column, :text
rename_column :models, :column_j, :column
end
您希望在迁移之前备份数据库。希望你再也不会考虑再次使用serialize
,serialize
是一个可怕的解决方案,似乎是一个简单的解决方案,但很快变成了一个瞄准你的RPG。