我试图从Mailchimp中提取一些嵌套哈希中返回的数据。这是我得到的结果的精简版。对于每封电子邮件,有多个GROUPINGS,每个GROUPING有多个GROUPS。
我的目标是将其放入一个mysql表,其布局如下:email_addr,list,grouping1_id,grouping1_name,group1_name,group1_interest,group2_name,group2_interest,grouping2_id,grouping2_name等。因此,每个订阅者都有一行所有分组和组信息。
{"email"=>"dummy@gmail.com", "merges"=>{"EMAIL"=>"dummy@gmail.com",
"GROUPINGS"=>[{"id"=>1, "name"=>"Grouping One", "groups"=>[{"name"=>"Group One",
"interested"=>false}, {"name"=>"Group", "interested"=>true},
{"name"=>"Group Three", "interested"=>true}]}, {"id"=>2, "name"=>"Grouping Two",
"groups"=>[{"name"=>"Group Four", "interested"=>false},
{"name"=>"Group Five", "interested"=>false}]}]}}
现在,我运行的代码运行并将嵌套块的结果插入表中,但每次通过groups.each_with_index语句都有一行。到目前为止,我的方法看起来过于复杂,但我不确定如何正确处理数据。
感谢任何帮助。
更新: 我稍微清理了逻辑并将数据库写入分离到散列处理的每个级别。现在正确地在数据库中插入和更新数据。虽然这仍然感觉非常不优雅。
def organize_members_subs
@members_data = @members_subs["data"]
@members_data.each do |member|
@email_addr = member["email"]
@db.query("INSERT INTO db.details
(email_addr, list)
VALUES ('#{@email_addr}', '#{@list}' ) ")
groupings = member["merges"]["GROUPINGS"]
groupings.each_with_index do |grouping, index|
@groupings_name = grouping["name"]
@groupings_id = grouping["id"]
@groupings_label = "grp#{index}_"
@db.query("UPDATE db.details
SET grouping#{index}_id = '#{@groupings_id}'
, grouping#{index}_name = '#{@groupings_name}'
WHERE email_addr = '#{@email_addr}' ")
groups = member["merges"]["GROUPINGS"][index]["groups"]
groups.each_with_index do |group, index|
@group_name = group["name"]
@group_interested = group["interested"]
@db.query("UPDATE db.details
SET #{@groupings_label}group#{index}_name = '#{@group_name}'
, #{@groupings_label}group#{index}_int = '#{@group_interested}'
WHERE email_addr = '#{@email_addr}' ")
break if index == groups.length
end
break if index == groupings.length
end
end
end
答案 0 :(得分:1)
首先,也许是额外的,但我喜欢使用符号,因为我在Rails中做了很多工作。所以,让我们从这里偷取一个方法:How do I convert a Ruby hash so that all of its keys are symbols?
def recursive_symbolize_keys(h)
case h
when Hash
Hash[
h.map do |k, v|
[ k.respond_to?(:to_sym) ? k.to_sym : k, recursive_symbolize_keys(v) ]
end
]
when Enumerable
h.map { |v| recursive_symbolize_keys(v) }
else
h
end
end
好的,让我们构建一个类,以便在需求变化时更容易操作和扩展:
class MemberSub
attr_accessor :email, :groupings, :data_hash, :list, :data_row, :db_sql
def initialize(data_hash)
#convert all keys to symbols
@data_hash = recursive_symbolize_keys(data_hash)
@email = @data_hash[:email]
@list = 'Members'
@groupings = @data_hash[:merges][:GROUPINGS]
@data_row = data_row
@db_sql = db_insert
end
def data_row
#returns a data row for DB
row_hash = {}
row_hash['email'] = @email
row_hash['list'] = @list
gc = 1
#iterate through groupings
@groupings.each_with_index do |grouping, index|
row_hash["grouping#{index + 1}_id"] = grouping[:id]
row_hash["grouping#{index + 1}_name"] = grouping[:name]
#iterate through the groups
grouping[:groups].each do |group|
row_hash["group#{gc}_name"] = group[:name]
row_hash["group#{gc}_interest"] = group[:interested]
gc += 1
end
end
row_hash
end
def db_insert
"INSERT INTO db.details (#{@data_row.keys}) VALUES (#{@data_row.values})".tr('[]','')
end
end
现在你可以使用迭代方法连续输入它并创建一个新对象:
row = MemberSub.new({"email"=>"dummy@gmail.com", "list"=>"Members", "merges"=>
{"EMAIL"=>"dummy@gmail.com", "GROUPINGS"=>[{"id"=>1, "name"=>"Grouping One", "groups"=>
[{"name"=>"Group One", "interested"=>false}, {"name"=>"Group Two", "interested"=>true},
{"name"=>"Group Three", "interested"=>true}]}, {"id"=>2, "name"=>"Grouping Two", "groups"=>
[{"name"=>"Group Four", "interested"=>false}, {"name"=>"Group Five", "interested"=>false}]}]}})
并进行查询:
db.query(row.db_sql)
db.query(INSERT INTO db.details ("email", "list", "grouping1_id", "grouping1_name",
"group1_name", "group1_interest", "group2_name", "group2_interest", "group3_name",
"group3_interest", "grouping2_id", "grouping2_name", "group4_name", "group4_interest",
"group5_name", "group5_interest") VALUES ("dummy@gmail.com", "Members", 1, "Grouping One",
"Group One", false, "Group Two", true, "Group Three", true, 2, "Grouping Two", "Group Four",
false, "Group Five", false))
其他方法应该是自我解释的。您不必将它们全部用作attar_accessor
,但我只是这样做了。
答案 1 :(得分:1)
首先,我想仔细看看你的哈希值。我没有自己重新格式化,而是这样做了:
require "awesome_print"
h = `{"email"=>..., "interested"=>false}]}]}}`
ap h
向下滚动到我的答案底部,查看ap的哈希格式。
我会回答你的问题,假设db结构是给定的,但是想提出几点:
"id"
对于每个grouping
记录都是唯一的,您是否可以将其作为密钥,并取消index
?"name"
对于每个grouping
记录都是唯一的,那么您是否可以省略"id"
和index
?"name"
对于每个group
记录都是唯一的(对于给定的grouping
),您是否只为每个组group["name"] => group["interested"]
?继续您的代码,我还将假设您的哈希结构。稍后,我将重新审视这一假设。
我对你的代码提出的修改是相当小的,有些是纯粹的风格:
def organize_members_subs
。groupings_id = grouping["id"]
,然后是SET grouping#{index}_id = '#{@groupings_id}'
,只有SET grouping#{index}_id = '#{grouping["id"]}'
。
两个可能的例外是groupings
和groups
。例如,你可以通过写作摆脱前者
member["merges"]["GROUPINGS"].each_with_index do |grouping, index_1|
。我会把它们作为变量(所以我可以很容易地检查它们的值),
但这是一个风格决定。index
中的变量groupings.each_with_index do |grouping, index|
在内部块的范围内,它使用具有相同名称的迭代器变量。
我认为后者优先,但它们的名称应该不同。我已将它们分别更改为index_out
和index_in
。index_out
的范围从0
到groupings.length-1
,因此永远不会执行break if index_out == groupings.length
,因此可能会被删除。同上break if index_in == groups.length
。 groupings_label = "grp#{index}_"
,以引起人们注意这样一个事实,即只在以后需要它,而不是在前面的SET
表达式中。这些更改导致以下结果:
def organize_members_subs(db, list, @members_subs["data"])
members_data.each do |member|
email_addr = member["email"]
db.query("INSERT INTO db.details
(email_addr, list)
VALUES ('#{email_addr}', '#{list}' ) ")
groupings = member["merges"]["GROUPINGS"]
groupings.each_with_index do |grouping, index_out|
db.query("UPDATE db.details
SET grouping#{index_out}_id = '#{grouping["id"]}'
, grouping#{index_out}_name = '#{grouping["name"]}'
WHERE email_addr = '#{email_addr}' ")
groupings_label = "grp#{index_out}_"
groups = member["merges"]["GROUPINGS"][index_out]["groups"]
groups.each_with_index do |group, index_in|
db.query("UPDATE db.details
SET #{groupings_label}group#{index_in}_name = '#{group["name"]}'
, #{groupings_label}group#{index_in}_int = '#{group["interested"]}'
WHERE email_addr = '#{email_addr}' ")
end
end
end
end
看看你的哈希,我想知道你是否可以将它简化为以下内容(格式礼貌的真棒版画):
{
"email" => "dummy@gmail.com",
"merges" => {
"EMAIL" => "dummy@gmail.com",
"GROUPINGS" => {
1 => {
"name" => "Grouping One",
"groups" => {
"Group One" => false,
"Group Two" => true,
"Group Three" => true
}
},
2 => {
"name" => "Grouping Two",
"groups" => {
"Group Four" => false,
"Group Five" => false
}
}
}
}
}
甚至
{
"email" => "dummy@gmail.com",
"merges" => {
"EMAIL" => "dummy@gmail.com",
"GROUPINGS" => {
"Grouping One" => {
"Group One" => false,
"Group Two" => true,
"Group Three" => true
},
"Grouping Two" => {
"Group Four" => false,
"Group Five" => false
}
}
}
}
这些不仅仅是建议,而只是值得深思。
应用于哈希的真棒打印:
ap h # =>
{
"email" => "dummy@gmail.com",
"merges" => {
"EMAIL" => "dummy@gmail.com",
"GROUPINGS" => [
[0] {
"id" => 1,
"name" => "Grouping One",
"groups" => [
[0] {
"name" => "Group One",
"interested" => false
},
[1] {
"name" => "Group",
"interested" => true
},
[2] {
"name" => "Group Three",
"interested" => true
}
]
},
[1] {
"id" => 2,
"name" => "Grouping Two",
"groups" => [
[0] {
"name" => "Group Four",
"interested" => false
},
[1] {
"name" => "Group Five",
"interested" => false
}
]
}
]
}
}