使用包含数组的键遍历哈希数组
Loop through array of hash with a key containing an array
我想用一个包含数组的键遍历哈希数组。
我解释一下:
- 我有一个
stores
table
- 我有一个
products
table
- 我有一个
store_exluded_product
table 有一个 store_id
列和一个 product_id
列
我有这个哈希数组:
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
我想用一个包含数组的键遍历哈希数组。
我解释一下:
- 我有一个
stores
table - 我有一个
products
table - 我有一个
store_exluded_product
table 有一个store_id
列和一个product_id
列
我有这个哈希数组:
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