简体   繁体   English

如何使用 ActiveRecord json 字段类型

[英]How to use the ActiveRecord json field type

I have a Rails model which has a database column of type "json":我有一个 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

Great!伟大的! Now how do I use it?现在我该如何使用它? Is it really just as simple as treating the field like a Hash ?它真的像将字段视为Hash一样简单吗?

self.game_board[:player1] = 1
self.game_board[:cards] = cards.to_hash

If I were to write that, would everything just work as expected, so in a future API call from a client I could do this?:如果我这样写,一切都会按预期工作,所以在未来来自客户端的 API 调用中,我可以这样做吗?:

self.game_board[:player] # And get back the 1 that I put here before

What about performance as well?性能呢? Will the entire game_board be de-serialized every time even if that field is never read?即使从未读取该字段,每次都会对整个game_board进行反序列化吗? Will the field be re-written (IOW a database write) each time I change part of the "Hash?"每次更改“哈希”的一部分时,是否会重新写入该字段(IOW 数据库写入)?

Yes, ActiveRecord allows to use Postgres' json -fields simply as Hashes in their models.是的,ActiveRecord 允许将 Postgres 的json字段简单地用作其模型中的哈希。 However, there are a couple of things to consider:但是,有几件事情需要考虑:

  1. Hash may be NULL on initialization初始化时哈希可能为 NULL
    In your create_table migration you allow the field :game_board to be NULL .在您的create_table迁移中,您允许字段:game_boardNULL Thus, on first usage the field :game_board of your model-instance will be NULL and you have to initialize the Hash first before using it.因此,在第一次使用时,您的模型实例的字段:game_board将为NULL ,您必须在使用它之前先初始化 Hash。 (See example below) (见下例)

  2. In JSON all keys are Strings在 JSON 中,所有键都是字符串
    Thus, on save (and reload) all keys will be transformed into Strings if you have used Symbols or Numbers before.因此,如果您之前使用过符号或数字,则在保存(和重新加载)时,所有键都将转换为字符串。 Thus, to prevent unwanted behavior it is recommended to use String-keys unless your ORM is configured to symbolize all keys.因此,为了防止不需要的行为,建议使用字符串键,除非您的 ORM 配置为符号化所有键。


Your examples:你的例子:

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)


@ Performance: @ 表现:

  1. Yes, every time ActiveRecord reads an entry from the database and creates a model-instance, JSON-fields get unserialized into Hashes.是的,每次 ActiveRecord 从数据库读取条目并创建模型实例时,JSON 字段都会被反序列化为哈希。 But if you think that is a performance-hit to your application than you should either use a text-field and serialize/deserialize the JSON/Hashes when you need to or, even better, don't use ActiveRecord at all.但是,如果您认为这会影响您的应用程序的性能,那么您应该使用文本字段并在需要时序列化/反序列化 JSON/哈希,或者甚至更好,根本不使用 ActiveRecord。 By creating heaps of classes and using magic-methods, ActiveRecord creates so much overhead that you shouldn't worry about the deserialization of JSON.通过创建类堆并使用魔术方法,ActiveRecord 会产生如此多的开销,您不必担心 JSON 的反序列化。 Convenience has its costs.便利是有代价的。

  2. Yes, every time you change a value in the Hash, the (whole) JSON-field gets replaced and updated with the new serialized version.是的,每次更改 Hash 中的值时,(整个)JSON 字段都会被替换并更新为新的序列化版本。
    Two notes on this:对此有两点说明:

    • Even in Postgres itself (not only in ActiveRecord) the possibility of performing updates on certain JSON-elements is missing until now.即使在 Postgres 本身(不仅在 ActiveRecord 中),在某些 JSON 元素上执行更新的可能性直到现在也是缺失的。 Compare this Stackoverflow-question 比较这个 Stackoverflow 问题
    • In general, JSON-fields should be used with a fixed structure or, at least, in manageable sizes and the field-type is not supposed to be a document-store like eg.一般来说,JSON 字段应该与固定结构一起使用,或者至少以可管理的大小使用,并且字段类型不应该是像例如这样的文档存储。 in MongoDB.在 MongoDB 中。 Compare the Postgres documentation 比较 Postgres 文档

Just to further clarify - when you're saving the JSON object to an attribute of your model instance make sure to save it as a hash .只是为了进一步澄清 - 当您将 JSON 对象保存到模型实例的属性时,请确保将其保存为 hash

Active Record will not complain if you forget to parse a JSON string :如果您忘记解析 JSON字符串, Active Record 不会抱怨:

  game = Game.create(game_board: '"key":"value"')

When you retrieve a string from a json attribute, it won't complain and just return the String.当您从json属性中检索字符串时,它不会抱怨,只会返回字符串。

  game.game_board
  => '"key":"value"'

Thus game.game_board['key'] would lead to an error because you're trying to treat a String like a Hash.因此game.game_board['key']会导致错误,因为您试图将 String 视为 Hash。

So make sure you use JSON.parse(string) before saving.因此,请确保在保存之前使用JSON.parse(string)

  game = Game.create(game_board: JSON.parse('"key":"value"'))

So now you have the expected behavior所以现在你有了预期的行为

game.game_board['key']
=> 'value'

Probably not useful for this case, but came across this issue when saving a JSON payload from an API I was integrating with.在这种情况下可能没有用,但是在从我正在集成的 API 中保存 JSON 有效负载时遇到了这个问题。 Anyway, hope this helps.无论如何,希望这会有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM