ale*_*zko 2 postgresql activerecord ruby-on-rails rails-activerecord
我有一个模型,它有一列看起来像这样(示例):
column = [{:A => "1", :B => "2"}, [a, b, c, ..., n]]
Run Code Online (Sandbox Code Playgroud)
其中a,b,c和n也哈希,像这样(例子):
a = {:X => "x", :Y => "y"}
Run Code Online (Sandbox Code Playgroud)
目前,如果我调用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")
Run Code Online (Sandbox Code Playgroud)
错误说:
PG::SyntaxError: ERROR: syntax error at or near ":"
Run Code Online (Sandbox Code Playgroud)
编辑:
column是一种text数据类型
,在它的模型中它有serialize :column, Array
你的问题是你serialize用来存储你的数据,serialize只是将一大堆不可查询的 YAML 倾倒到数据库中。在 PostgreSQL 中解析 YAML 当然是可能的,但它会很慢而且有点毫无意义。
如果你真的需要存储一个哈希数组,那么 PostgreSQL 的jsonb类型将是你最好的选择。你不会在数据库中得到符号键,但你会得到字符串键,所以这个 Ruby 数据:
[{:A => "1", :B => "2"}, {:C => 6, :D => 11}]
Run Code Online (Sandbox Code Playgroud)
看起来像这个 JSON:
[ { "A": "1", "B": "2" }, { "C": 6, "D": 11 } ]
Run Code Online (Sandbox Code Playgroud)
数据库里面。
进入jsonb数据库后,您可以使用PostgreSQL 提供的所有JSON 函数和运算符查询它,甚至可以索引 JSON 以支持更快的查询。在您的情况下,您的查询将如下所示:
Model.where("column->0->>'A' = ?", '1')
Run Code Online (Sandbox Code Playgroud)
->RHS 上带有整数的运算符的作用类似于 Ruby 的Array#[]方法:
->int
获取 JSON 数组元素(从零开始索引,负整数从末尾开始计数)
RHS 上有一个字符串,它的作用类似于 Ruby 的Hash#[]. 请注意,->返回 JSON,而不是文本或整数。该->>操作是一样的->,但是这样你会使用,在年底作出比较清洁它返回文本。
或者你可以说:
Model.where("column->0->'A' = ?", '1'.to_json)
Run Code Online (Sandbox Code Playgroud)
将 string-vs-JSON 逻辑推送到 Ruby 中。
一旦您的数据库模式有意义(即它使用 PostgreSQLjsonb而不是 Rails 的serialize),一切都变得非常简单,但是您如何从这里到达那里?首先serialize :column, Array从您的模型中删除,然后您需要进行三步迁移,如下所示:
添加一jsonb列:
def change
add_column :models, :column_j, :jsonb
end
Run Code Online (Sandbox Code Playgroud)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
Run Code Online (Sandbox Code Playgroud)
请注意,您不能为此使用模型作为模型类,并且数据库不再同意models表的结构和格式。
用column新的替换旧的column_j:
def change
remove_column :models, :column, :text
rename_column :models, :column_j, :column
end
Run Code Online (Sandbox Code Playgroud)当然,您需要在迁移之前备份您的数据库。希望你永远不会再考虑使用serialize,这serialize是一个可怕的混合体,它看起来是一个简单的解决方案,但很快就会变成一个瞄准你脚下的角色扮演游戏。
| 归档时间: |
|
| 查看次数: |
2110 次 |
| 最近记录: |