Rails按列分组并选择列。

8
我有一个名为DinnerItem的表格,包括id、name、project_id、client_id、item_id和item_quantity这些列。
我想按照item_id这一列分组获取数据,其值应该只包含item_quantity列的值,并且格式如下:
{ item_id1 => [ {item_quantity from row1}, {item_quantity from row2}],
  item_id2 => [ {item_quantity from row3}, {item_quantity from row4} ]
}

如何在一次查询中实现它?
OfferServiceModels::DinnerItem.all.select('item_id, item_quantity').group_by(&:item_id)

但是这个格式如下:
 {1=>[#<DinnerItem id: nil, item_id: 1, item_quantity: nil>, #<DinnerItem id: nil, item_id: 1, item_quantity: {"50"=>30, "100"=>10}>], 4=>[#<DinnerItem id: nil, item_id: 4, item_quantity: {"100"=>5, "1000"=>2}>}
3个回答

17
类似下面的内容就可以完成任务了:
result = OfferServiceModels::DinnerItem
  .pluck(:item_id, :item_quantity)
  .group_by(&:shift)
  .transform_values(&:flatten)
#=> {1 => [10, 20], 2 => [30, 40]}
#    ^ item id            ^^  ^^ item quantity

一步一步的解释:
# retrieve the item_id and item_quantity for each record
result = OfferServiceModels::DinnerItem.pluck(:item_id, :item_quantity)
#=> [[1, 10] [1, 20], [2, 30], [2, 40]]
#     ^ item id           ^^ item quantity

# group the records by item id, removing the item id from the array
result = result.group_by(&:shift)
#=> {1 => [[10], [20]], 2 => [[30], [40]]}
#    ^ item id                 ^^    ^^ item quantity

# flatten the groups since we don't want double nested arrays
result = result.transform_values(&:flatten)
#=> {1 => [10, 20], 2 => [30, 40]}
#    ^ item id            ^^  ^^ item quantity

参考文献:


这是在joins之后按列分组的完美解决方案。 - Purple_Kitten

3
您可以保留查询和分组,但需要在操作末尾添加 as_json
DinnerItem.select(:item_id, :item_quantity).group_by(&:item_id).as_json
# {"1"=>[{"id"=>nil, "item_id"=>1, "item_quantity"=>1}, {"id"=>nil, "item_id"=>1, "item_quantity"=>2}],
#  "2"=>[{"id"=>nil, "item_id"=>2, "item_quantity"=>1}, {"id"=>nil, "item_id"=>2, "item_quantity"=>2}]}

请注意,as_json方法将添加每一行的id属性,即使该属性的值为空。


2

我不知道在不转换从数据库返回的值的情况下是否可能实现此目标。如果您能够进行转换,则以下内容应该可以按照您所需的格式工作:

OfferServiceModels::DinnerItem.all.select('item_id, item_quantity').group_by(&:item_id)
                              .transform_values { |vals| vals.map(&:item_quantity) }
# => {"1"=>[nil,{"50"=>30, "100"=>10}],"4"=>...}

# or

OfferServiceModels::DinnerItem.all.select('item_id, item_quantity').group_by(&:item_id)
                              .transform_values { |vals| vals.map { |val| val.slice(:item_quantity) }
 # => {"1"=>[{:item_quantity=>nil},:item_quantity=>{"50"=>30, "100"=>10}}],"4"=>...}

我认为直接从数据库中获取的输出没有任何问题。数据已经存在,因此在需要时输出相关字段:可以通过上述转换或在遍历数据时实现。希望这能有所帮助,请告诉我 :)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接