【问题标题】:Ruby Rails - Structuring Nested ObjectsRuby Rails - 构建嵌套对象
【发布时间】:2017-05-18 06:47:49
【问题描述】:

在我当前的项目中,我收到了一个大型 JSON 文件,我正在对其进行解析并存储到我的数据库中。问题是我觉得我正在以一种非常低效的方式构建我的数据库。

JSON 示例:

{
    first_name: "John",
    records: {
     ids: [110, 725, 2250],
     count: [1, 1, 6]
      },
    items: {
        top: {
            title: "My top",
            values: {  value: [51, 50, 70] }
        },
        middle: {
            title: "Middle Stuff",
            values: { value: [51] }
        },
    },
    values: {
        health: 100,
        strength: 250,
        mana: 50
    }
}

如您所见,JSON 相当复杂,带有嵌套的对象。

在构建它时,我从主对象 (user) 开始,然后慢慢开始添加更多对象。 Values 很简单,所以我将其添加为另一个表,并仅引用 user_id。

然后我做了records,这有点复杂,但有效。但是,我非常担心嵌套最多的部分,可能是 5+ 个对象深。我觉得我不应该为一个简单的值设置一整列。

改善这一点的最佳方法是什么?我应该以某种方式处理数据并以不同的方式存储吗?

感谢您的帮助。

【问题讨论】:

  • 您打算以后如何使用这些数据?您是一次需要所有数据,还是计划对数据运行复杂的查询或计算?您是否考虑过文档数据存储或 JSONB 列?你想优化写入或读取的数据结构,更重要的用例是什么?
  • 我计划在收到数据后运行一些计算,存储结果,但稍后我需要显示部分数据。例如,我需要顶部的标题和稍后显示的值。全部在显示整个用户对象时同时进行。我主要担心读回对象,写作不应该经常发生。而且我还没有真正研究过任何其他类型,例如 JSONB。
  • 创建一个合适的User 模型可能是一个更好的主意,而不是使用所有需要的属性并在保存时进行计算。
  • 比如,当我得到所有的 JSON 时,找到我需要的方面,然后保存它们?这听起来像是我想做的事情,但我也想保持面向对象的东西,怎么说呢,取values 对象,并将其作为代码中的对象保存,但将其存储为,如 JSON在数据库中?
  • 如果用户只有health(例如),那么拥有与用户 1:1 关联的专用值表没有任何好处。只需将health、strength、mana 列直接添加到用户表中。如果用户可能有多个健康值,则创建一个新表并使其成为 has_many 关联。在不了解您的要求以及如何定义关联的情况下,很难就数据和表结构向您提供建议。 item、value、record 非常通用,我不确定它们在您的域中是如何连接的。

标签: ruby-on-rails json ruby database


【解决方案1】:

// JSON 响应

{
    "name": "John Smith",
    ...
    "progression": {
        "levels": [{
            "name": "Level 1",
            "bosses": [
            {
                "name": "Boss 1",
                "difficultyCompleted": "Hard"
            },
            {
                "name": "Boss 2",
                "difficultyCompleted": "Hard"
            }]
        },{
            "name": "Level 2",
            "bosses": [
            {
                "name": "Boss 3",
                "difficultyCompleted": "Normal"
            },
            {
                "name": "Boss 4",
                "difficultyCompleted": "Easy"
            }]
        }
    }
}

在这个 JSON 示例中,用户完成的每个老板都有几层。我最初想做的是创建模型和表格,但这似乎不仅浪费内存,而且还需要更长的时间才能获取Boss 4 的当前进度。

例子:

User has_one Progression. 
Progression has_one Levels. 
Levels has_many Dungeons. 
Dungeons has_many bosses.

我所做的是尝试将 bosses 压缩到单个字段中,并在运行时转换 JSON。

所以,我的结构应该是这样的。

User has_one Progression.
Progression has_many Dungeons.

型号: // Progression.rb

class Progression < ApplicationRecord

    has_many :dungeons

    def self.initialize(params={})
        params = params['levels']

        prog = Progression.new()

        params.each do |dungeon|
            prog.dungeons.append( Dungeon.initialize( dungeon ) )
        end

        return prog
    end
end

// 地牢.rb

class Dungeon < ApplicationRecord
    belongs_to :progression

    def self.initialize(params={})
        Dungeon.new(params.reject { |k| !Dungeon.attribute_method?(k) }) # Used to ignore any unused parameters that don't exist on the model.
    end

    # To convert `bosses` from JSON into a hash for easy use.
    def get_bosses
        JSON.parse bosses.gsub( '=>', ':' )
    end
end

迁移: // xxxxxx_create_progression.rb

class CreateProgression < ActiveRecord::Migration[5.0]
  def change
    create_table :progressions do |t|
        t.integer :character_id
    end

    create_table :dungeons do |t|
        t.integer :character_id
        t.integer :progression_id

        t.string :name
        t.text :bosses
    end

    add_index :progressions, :character_id
    add_index :dungeons, :progression_id
end
end

现在,当更新用户以获取他们的进度时,我可以设置他们的进度。

// users_controller.rb

def update_progression
    progression = ... fetched from the response

    @user.progression = Progression.initialize(progression)
end

将所有内容保存给用户后,您现在可以通过以下方式获取进度:

<% user.progression.dungeons.each do |dungeon| %>
    <%= dungeon.name %>
<% end %>

这个解决方案似乎是一个不错的组合,但我有点担心 JSON 的解析。它可能会变得太多,但我必须继续观察它。任何其他想法或改进将不胜感激。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多