遍历记录集合并将对象传回前端的最佳方法是什么?
What is the best way to loop through a collection of records and pass back an object to the front end?
我有一个 returns 用户报告的控制器,其中一种方法总结了每个用户所述报告的要点。我想把这个数据的一个对象传回给前端,这样就可以显示了。理想情况下,我的对象的形状应该是这样的:
data: {
users: {
$user_id: {
name: "Foo Bar",
points: 100
},
$user_id: {
name: "Foo Bar Two",
points: 10
}
}
}
然而我目前的实现并不是像这样构建对象,而是简单地添加到一个大对象中。
我的代码如下所示:
def user_points
hash = {}
User.all.each do |u|
user_points = Report.select("points").where("user_id = ?", u.id).sum("points")
hash.merge!(
user:
{
first_name: u.first_name,
last_name:u.last_name,
time_zone: u.time_zone
}
)
end
render json: { data: hash }
end
并且生成的对象只包含一个大对象中的最后一个用户
data:
user:
first_name: "Test"
last_name: "Test"
points: 200
time_zone: "Pacific Time (US & Canada)"
如 dbugger 所述,您需要为每个哈希条目提供唯一键,否则合并将仅替换现有值。
例如:
{a: :foo}.merge(b: :bar)
=> {:a=>:foo, :b=>:bar}
和
{a: :foo}.merge(b: :bar).merge(a: :foo_bar)
{:a=>:foo_bar, :b=>:bar}
您可能要考虑返回 json 数组而不是具有唯一 属性 名称的对象。
也许是这样的?
def user_points
result = User.all.map do |u|
points = Report.select("points").where("user_id = ?", u.id).sum("points")
{
first_name: u.first_name,
last_name:u.last_name,
time_zone: u.time_zone
points: points
}
end
render json: { data: result }
end
您也可以通过连接 table 然后对连接的 table 执行聚合来获得相同的结果。
select users.id, users.name, sum(reports.points) as points from users join reports on users.id = reports.user_id group by users.id;
谢谢 max 的评论。
def user_points
result = User.join(:reports)
.select(
:first_name,
:last_name,
Report.arel_table[:points].sum.as(:points),
:time_zone
)
.group(:id)
render json: { data: result }
end
输出:
data:
first_name: "Test1"
last_name: "Test1"
points: 100
first_name: "Test2"
last_name: "Test2"
points: 200
first_name: "Test3"
last_name: "Test3"
points: 300
我有一个 returns 用户报告的控制器,其中一种方法总结了每个用户所述报告的要点。我想把这个数据的一个对象传回给前端,这样就可以显示了。理想情况下,我的对象的形状应该是这样的:
data: {
users: {
$user_id: {
name: "Foo Bar",
points: 100
},
$user_id: {
name: "Foo Bar Two",
points: 10
}
}
}
然而我目前的实现并不是像这样构建对象,而是简单地添加到一个大对象中。
我的代码如下所示:
def user_points
hash = {}
User.all.each do |u|
user_points = Report.select("points").where("user_id = ?", u.id).sum("points")
hash.merge!(
user:
{
first_name: u.first_name,
last_name:u.last_name,
time_zone: u.time_zone
}
)
end
render json: { data: hash }
end
并且生成的对象只包含一个大对象中的最后一个用户
data:
user:
first_name: "Test"
last_name: "Test"
points: 200
time_zone: "Pacific Time (US & Canada)"
如 dbugger 所述,您需要为每个哈希条目提供唯一键,否则合并将仅替换现有值。
例如:
{a: :foo}.merge(b: :bar)
=> {:a=>:foo, :b=>:bar}
和
{a: :foo}.merge(b: :bar).merge(a: :foo_bar)
{:a=>:foo_bar, :b=>:bar}
您可能要考虑返回 json 数组而不是具有唯一 属性 名称的对象。
也许是这样的?
def user_points
result = User.all.map do |u|
points = Report.select("points").where("user_id = ?", u.id).sum("points")
{
first_name: u.first_name,
last_name:u.last_name,
time_zone: u.time_zone
points: points
}
end
render json: { data: result }
end
您也可以通过连接 table 然后对连接的 table 执行聚合来获得相同的结果。
select users.id, users.name, sum(reports.points) as points from users join reports on users.id = reports.user_id group by users.id;
谢谢 max 的评论。
def user_points
result = User.join(:reports)
.select(
:first_name,
:last_name,
Report.arel_table[:points].sum.as(:points),
:time_zone
)
.group(:id)
render json: { data: result }
end
输出:
data:
first_name: "Test1"
last_name: "Test1"
points: 100
first_name: "Test2"
last_name: "Test2"
points: 200
first_name: "Test3"
last_name: "Test3"
points: 300