如何使用 ActiveRecord json 字段类型
Posted
技术标签:
【中文标题】如何使用 ActiveRecord json 字段类型【英文标题】:How to use the ActiveRecord json field type 【发布时间】:2015-01-23 03:11:14 【问题描述】:我有一个 Rails 模型,它有一个“json”类型的数据库列:
create_table "games", force: true do |t|
t.json "game_board"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
太棒了!现在我该如何使用它?真的像treating the field like a Hash
一样简单吗?
self.game_board[:player1] = 1
self.game_board[:cards] = cards.to_hash
如果我写这个,一切都会按预期工作吗,所以在未来来自客户端的 API 调用中我可以这样做吗?:
self.game_board[:player] # And get back the 1 that I put here before
性能呢?即使从未读取过该字段,整个game_board
是否每次都会被反序列化?每次我更改部分“哈希”时,该字段是否会被重写(IOW 数据库写入)?
【问题讨论】:
【参考方案1】:是的,ActiveRecord 允许在其模型中简单地使用 Postgres 的 json
-fields 作为哈希。但是,有几点需要考虑:
初始化时哈希可能为 NULL
在您的 create_table
迁移中,您允许字段 :game_board
为 NULL
。因此,在第一次使用时,模型实例的字段:game_board
将是NULL
,并且您必须在使用它之前先初始化哈希。 (见下面的例子)
在 JSON 中,所有键都是字符串 因此,如果您之前使用过符号或数字,则在保存(和重新加载)时所有键都将转换为字符串。因此,为了防止不必要的行为,除非您的 ORM 配置为符号化所有键,否则建议使用字符串键。
你的例子:
self.game_board ||=
self.game_board[:player1] = 1
self.game_board[:cards] = cards.to_hash
# after reload from database (access via String-key):
self.game_board['player1'] # And retrieve value 1 (that we put here before)
@性能:
是的,每次 ActiveRecord 从数据库读取条目并创建模型实例时,JSON 字段都会被反序列化为哈希。但是,如果您认为这会对您的应用程序造成性能影响,那么您应该在需要时使用文本字段并序列化/反序列化 JSON/哈希,或者甚至更好的是,根本不使用 ActiveRecord。通过创建类堆和使用魔法方法,ActiveRecord 产生了如此多的开销,您不必担心 JSON 的反序列化。便利是有代价的。
是的,每次更改 Hash 中的值时,(整个)JSON 字段都会被替换并更新为新的序列化版本。 对此有两点说明:
即使在 Postgres 本身中(不仅在 ActiveRecord 中),对某些 JSON 元素执行更新的可能性也一直缺失。 Compare this ***-question 一般来说,JSON 字段应该使用一个固定的结构,或者至少是在可管理的大小中,并且字段类型不应该是一个文档存储,例如。在 MongoDB 中。 Compare the Postgres documentation【讨论】:
【参考方案2】:进一步澄清 - 当您将 JSON 对象保存到模型实例的属性时确保将其保存为哈希。
如果您忘记解析 JSON 字符串,Active Record 不会抱怨:
game = Game.create(game_board: '"key":"value"')
当您从json
属性中检索字符串时,它不会报错而只是返回字符串。
game.game_board
=> '"key":"value"'
因此game.game_board['key']
会导致错误,因为您试图将字符串视为哈希。
所以请确保在保存之前使用JSON.parse(string)
。
game = Game.create(game_board: JSON.parse('"key":"value"'))
所以现在你有了预期的行为
game.game_board['key']
=> 'value'
在这种情况下可能没有用,但在从我正在集成的 API 保存 JSON 有效负载时遇到了这个问题。无论如何,希望这会有所帮助。
【讨论】:
以上是关于如何使用 ActiveRecord json 字段类型的主要内容,如果未能解决你的问题,请参考以下文章
使用 Activerecord、Rails 和 Postgres 查找具有多个重复字段的行
Mysql 5.7 json 数据类型,在 Rails 5 中使用 activerecord 查询
如何存储和比较:ActiveRecord 中的符号(Ruby on Rails)