【问题标题】:How to use the ActiveRecord json field type如何使用 ActiveRecord json 字段类型
【发布时间】: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 数据库写入)?

【问题讨论】:

    标签: ruby-on-rails json postgresql ruby-on-rails-4 activerecord


    【解决方案1】:

    是的,ActiveRecord 允许在其模型中简单地使用 Postgres 的 json-fields 作为哈希。但是,有几点需要考虑:

    1. 初始化时哈希可能为 NULL
      在您的 create_table 迁移中,您允许字段 :game_boardNULL。因此,在第一次使用时,模型实例的字段:game_board 将是NULL,并且您必须在使用它之前先初始化哈希。 (见下面的例子)

    2. 在 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)
    


    @性能:

    1. 是的,每次 ActiveRecord 从数据库读取条目并创建模型实例时,JSON 字段都会被反序列化为哈希。但是,如果您认为这会对您的应用程序造成性能影响,那么您应该在需要时使用文本字段并序列化/反序列化 JSON/哈希,或者甚至更好的是,根本不使用 ActiveRecord。通过创建类堆和使用魔法方法,ActiveRecord 产生了如此多的开销,您不必担心 JSON 的反序列化。便利是有代价的。

    2. 是的,每次更改 Hash 中的值时,(整个)JSON 字段都会被替换并更新为新的序列化版本。
      对此有两点说明:

      • 即使在 Postgres 本身中(不仅在 ActiveRecord 中),对某些 JSON 元素执行更新的可能性也一直缺失。 Compare this Stackoverflow-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 有效负载时遇到了这个问题。无论如何,希望这会有所帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-10-26
        • 2020-06-03
        • 2010-11-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-06-25
        • 2019-12-27
        相关资源
        最近更新 更多