使用包含数组的键遍历哈希数组

Loop through array of hash with a key containing an array

我想用一个包含数组的键遍历哈希数组。

我解释一下:

我有这个哈希数组:

array = [
  { :store_id => 5, :products_ids => [1, 4, 19, 40] },
  { :store_id => 13, :products_ids => [2, 20, 35] },
  # ...
]

我想用 StoreExcludedProduct.create() 为我的 StoreExludedProduct table 创建新的 ActiveRecord :

id store_id product_id
1 5 1
2 5 4
3 5 19
4 5 40
5 13 2
6 13 20
7 13 35

如果你对我的问题有一个好的解决方案,而且不会发出太多的数据库请求,我会非常高兴

谢谢

一种简单的方法是只迭代数组和产品 ID:

array.each do |hash|
  hash[:product_ids].each do |product_id|
    StoreExcludedProduct.create(
      store_id: hash[:store_id],
      product_id: product_id
    )
  end
end

您可以将上述代码包装在 transaction 调用中以避免每个 create 有单独的事务,即:

StoreExcludedProduct.transaction do
  array.each do |hash|
    # ...
  end
end

这也使您的代码 运行 成为孤注一掷的方式。

另一个选项是insert_all,它可以一次插入多条记录。为了使用它,您必须首先为每条记录构建一个属性数组,即您必须拆分产品 ID。这很像上面的代码:

attributes = array.flat_map do |hash|
  hash[:products_ids].map do |product_id|
    { store_id: hash[:store_id], product_id: product_id }
  end
end
#=> [
#   {:store_id=>5, :product_id=>1},
#   {:store_id=>5, :product_id=>4},
#   {:store_id=>5, :product_id=>19},
#   {:store_id=>5, :product_id=>40},
#   {:store_id=>13, :product_id=>2},
#   #...
# ]

可以传递给insert_all:

StoreExcludedProduct.insert_all(attributes)

请注意,这会执行原始 SQL 查询,而不会实例化任何模型或 运行 任何回调或验证。

您也可以使用导入方式,通过一次事务将所有记录插入数据库。

to_be_import = []
array.each do |h|
  h[:products_ids].each do |product_id|
    to_be_import << StoreExcludedProduct.new(h[:store_id],product_id)
  end
end

StoreExcludedProduct.import(
  to_be_import,
  validate: false,
  on_duplicate_key_update: {
    conflict_target: [:id],
    columns: [:store_id, :product_id]
  }
)

参考文献:activerecord-import