【发布时间】:2016-03-15 12:24:14
【问题描述】:
我该如何转:
Person.all.pluck(:id, :name)
到
[{id: 1, name: 'joe'}, {id: 2, name: 'martin'}]
不必对每个值进行 .map(因为当我从 .pluck 添加或删除时,我必须对 .map 做同样的事情)
【问题讨论】:
标签: ruby ruby-on-rails-4
我该如何转:
Person.all.pluck(:id, :name)
到
[{id: 1, name: 'joe'}, {id: 2, name: 'martin'}]
不必对每个值进行 .map(因为当我从 .pluck 添加或删除时,我必须对 .map 做同样的事情)
【问题讨论】:
标签: ruby ruby-on-rails-4
你可以map结果:
Person.all.pluck(:id, :name).map { |id, name| {id: id, name: name}}
正如@alebian 所说: 这比
Person.all.as_json(only: [:id, :name])
原因:
pluck 只返回使用的列 (:id, :name) 而其他解决方案返回所有列。根据表格的宽度(列数),这会产生很大的不同Person 对象,不需要为模型分配属性等等。相反,它只返回一个包含一个整数和一个字符串的数组。as_json 再次比简单的 map 开销更大,因为它是将模型转换为哈希的通用实现【讨论】:
select 解决方案似乎更好。
pluck 和map 中重复自己,但是与as_json(only:) 相比,巨大的性能提升远远超过了我使用中的代码复杂性案例。
你可以这样做
Person.select(:id,:name).as_json
你也可以试试
Person.all.as_json(only: [:id, :name])
【讨论】:
Person 模型中定义方法名称sum_of_fields,这将返回所需字段的总和。然后将该方法称为Person.all.as_json(methods: [:sum_of_fields])。有关更多详细信息,您可以阅读此documentation
[{id: nil, name: 'joe'}, {id: nil, name: 'martin'}] 而 Person.all.as_json(only: [:name]) 返回 [{name: 'joe'}, {name: 'martin'}] 所以对于不想要 id 的更一般的情况,第二种方法是更好。
Person.select(:id,:name).as_json 会更干净。
我看到三个选项:
1) pluck加map:
Person.pluck(:id, :name).map { |p| { id: p[0], name: p[1] } }
2) pluck plus map plus zip 和一个使其干燥的变量:
attrs = %w(id name)
Person.pluck(*attrs).map { |p| attrs.zip(p).to_h }
3) 或者您可能根本不使用pluck,尽管这样的性能要差得多:
Person.all.map { |p| p.slice(:id, :name) }
【讨论】:
.map()、.zip() 和.to_h 结合起来!感谢分享@spickermann
如果你使用postgresql,你可以在pluck方法中使用json_build_object函数:
https://www.postgresql.org/docs/9.5/functions-json.html
这样,你可以让 db 创建哈希。
Person.pluck("json_build_object('id', id, 'name', name)")
#=> [{id: 1, name: 'joe'}, {id: 2, name: 'martin'}]
【讨论】:
可以在 pluck 之后以 ID 为键,名称为值进行散列:
Person.all.pluck(:id, :name).to_h
{ 1 => 'joe', 2 => 'martin' }
不确定这是否符合您的需求,但作为一种选择。
【讨论】:
您可以为此使用恰当命名的 pluck_to_hash gem: https://github.com/girishso/pluck_to_hash
它将使用 pluck_to_hash 方法扩展 AR,其工作原理如下:
Post.limit(2).pluck_to_hash(:id, :title)
#
# [{:id=>213, :title=>"foo"}, {:id=>214, :title=>"bar"}]
#
Post.limit(2).pluck_to_hash(:id)
#
# [{:id=>213}, {:id=>214}]
它声称比使用 AR select 和 as_json 快几倍
【讨论】:
【讨论】:
pluck 经常用于性能,我想说的最有用的答案比这里的任何其他答案都更有效。
如果你有多个属性,你可以这样做以保持整洁:
Item.pluck(:id, :name, :description, :cost, :images).map do |item|
{
id: item[0],
name: item[1],
description: item[2],
cost: item[3],
images: item[4]
}
end
【讨论】:
最简单的方法是将pluck 方法与zip 方法结合使用。
attrs_array = %w(id name)
Person.all.pluck(attrs_array).map { |ele| attrs_array.zip(ele).to_h }
如果您在整个应用程序中使用此方法,您也可以创建一个辅助方法。
def pluck_to_hash(object, *attrs)
object.pluck(*attrs).map { |ele| attrs.zip(ele).to_h }
end
考虑通过将self 声明为默认接收者而不是将Person.all 作为object 变量进行修改。
阅读更多关于zip的信息。
【讨论】:
这是一种对我来说效果很好的方法:
def pluck_to_hash(enumerable, *field_names)
enumerable.pluck(*field_names).map do |field_values|
field_names.zip(field_values).each_with_object({}) do |(key, value), result_hash|
result_hash[key] = value
end
end
end
【讨论】:
我知道这是一个旧线程,但万一有人正在寻找更简单的版本
Hash[Person.all(:id, :name)]
在 Rails 5 中测试。
【讨论】: