我有一系列哈希。像这样......
transactions = [{"date"=>"2014-07-21", "amount"=>200},
{"date"=>"2012-06-21", "amount"=>400},
{"date"=>"2014-08-21", "amount"=>100},
{"date"=>"2014-08-12", "amount"=>150},
{"date"=>"2014-06-15", "amount"=>230}
{"date"=>"2013-05-21", "amount"=>900},]
我希望能够保存每个月的总金额,然后显示最近3个月到今天的日期及其总金额。像这样......
总计:06-14 230美元 07-14 200美元 08-14 $ 250
我有这种方法,但我不知道如何只将最近3个月放入我的数据库字段以及如何将其打印出来。
def income_by_month
@payroll_transactions = current_user.transactions
@recent_payroll = @payroll_transactions.find_all {90.days.ago.to_date..Date.today}.map #finds transactions within 90 days
@amount_by_month = @recent_payroll.group_by { |t| t.date.to_date.month }.map do |month, transactions|
[month, transactions.sum(:amount)] #Groups transactions by month and adds month total
end.to_h
- 编辑 -
我想出了一种方法,只是为了获取过去30天内的事务,我更新了我的方法以显示它。现在我的问题是如何保存答案(我将它作为数组保存在一个字段中吗?)然后如何在我的视图中显示答案。就像我在这里展示一样。如何在订单中逐行打印每个键和值?
Totals: 06-14 $230
07-14 $200
08-14 $250
CNC中 对不起我的数据库是一个mongoid db。我想将最近3个月保存到今天的日期,无论金额是否可用。
答案 0 :(得分:1)
让我先简单介绍一下您的代码段:
group_by { |t| t.date.to_date.month }
请注意,按单month
对对象进行分组不会花费一年的时间,因此它会在一个容器中结束2012年和2014年的交易金额。所以你真正想要的是根据月份和年份值进行分组。
考虑通过输入数组减少冗余迭代量(以及使用不必要的聚合),我得出了以下建议:
last_months = transactions.map{|i| Date.parse(i["date"]).strftime("%m-%Y")}.uniq.sort.last(3)
result = last_months.inject({}){|result, input| result[input] = 0; result}
transactions.inject(result) do |result, object|
# NOTE: we're already doing dates parsing and strftime two times here.
# In case you operate on Date objects themselves in your code, this is not the case.
# But the real perfomance measurement between summing all values up
# and strftiming more than once should be done additionally.
month = Date.parse(object["date"]).strftime("%m-%Y")
result[month] += object["amount"] if result[month]
result
end
# result now equals to {"06-2014"=>230, "07-2014"=>200, "08-2014"=>250}
首先,我们获得最近三个月(和几年)。
接下来,我们创建一个哈希,以包含仅包含最后几个月密钥的聚合值。最后,我们只对那些似乎是后3个月之一的交易总结amount
。
因此,只要ruby哈希值(ruby v.1.9 +)保留了键顺序,你可以简单地遍历它们以打印出来:
result.each{|k,v| puts "#{k}: #{v}"}
# 06-2014: 230
# 07-2014: 200
# 08-2014: 250
最后要注意的是,在服务器代码中进行这种聚合效率不高。更诱人的选择是将此计算移动到您的数据库层。
答案 1 :(得分:0)
ActiveSupport有一些漂亮的日期方法,比如Date#beginning_of_month:
require "date"
require "active_support/core_ext"
def process_transaction_group(month, transactions)
{
month: month.strftime("%Y/%m"),
total: transactions.map {|t| t["amount"] }.reduce(:+)
}
end
def process_transactions(transactions)
transactions
.group_by {|t| Date.parse(t["date"]).beginning_of_month }
.select {|month, _trxs| month < 3.months.ago }
.map {|month, trxs| process_transaction_group(month, trxs) }
end
###############
transactions = [{"date"=>"2014-07-21", "amount"=>200},
{"date"=>"2012-06-21", "amount"=>400},
{"date"=>"2014-08-21", "amount"=>100},
{"date"=>"2014-08-12", "amount"=>150},
{"date"=>"2014-06-15", "amount"=>230},
{"date"=>"2013-05-21", "amount"=>900}]
process_transactions(transactions)
#=> [{:month=>"2014/07", :total=>200}, {:month=>"2012/06", :total=>400}, {:month=>"2014/08", :total=>250}, {:month=>"2014/06", :total=>230}, {:month=>"2013/05", :total=>900}]