I have this sql query
Ticket.joins([assigned_user::departament],:ticket_status).group("ticket_statuses.name","departaments.name").where("ticket_statuses.status = ?", 1).count
what does this give me back
[ "Open", "BROWSER" ] => 2,
[ "Open", "MARKETING" ] => 5,
[ "Open", "MONITORING" ] => 2,
[ "Open", "SALES" ] => 7,
[ "Open", "ADMINISTRATION" ] => 8,
[ "Open", "COLLECTIONS" ] => 1,
[ "Open", "EMPLOYEE" ] => 8,
[ "Open", "SYSTEMS" ] => 6,
[ "Open", "QUALITY" ] => 4,
[ "Open", "TECH SUPPORT" ] => 5,
[ "Open", "STORE" ] => 2,
[ "Closed", "SYSTEMS" ] => 11,
[ "Closed", "MONITORING" ] => 7,
[ "Closed", "ADMINISTRATION" ] => 4,
[ "Closed", "QUALITY" ] => 6,
[ "Closed", "STORE" ] => 6,
[ "Closed", "EMPLOYEE" ] => 2,
[ "Closed", "SALES" ] => 3,
[ "Closed", "TECHNICAL SUPPORT" ] => 4,
[ "Closed", "BROWSER" ] => 1,
[ "Closed", "COLLECTIONS" ] => 2,
[ "Closed", "MARKETING" ] => 1,
[ "Attended", "QUALITY" ] => 3,
[ "Served", "EMPLOYEE" ] => 3,
[ "Served", "WAREHOUSE" ] => 5,
[ "Attended", "COLLECTIONS" ] => 3,
[ "Served", "SYSTEMS" ] => 8,
[ "Served", "SALES" ] => 5,
[ "Attended", "TECHNICAL SUPPORT" ] => 3,
[ "Attended", "BROWSER" ] => 8,
[ "Attended", "ADMINISTRATION" ] => 7,
[ "Attended", "MONITORING" ] => 3,
[ "Served", "MARKETING" ] => 2,
[ "In process", "EMPLOYEE" ] => 4,
[ "In process", "COLLECTIONS" ] => 2,
[ "In process", "QUALITY" ] => 7,
[ "In process", "MONITORING" ] => 4,
[ "In process", "BROWSER" ] => 4,
[ "In progress", "MARKETING" ] => 4,
[ "In process", "SYSTEMS" ] => 3,
[ "In process", "ADMINISTRATION" ] => 4,
[ "In process", "TECHNICAL SUPPORT" ] => 3,
[ "In process", "WAREHOUSE" ] => 3,
[ "In process", "SALES" ] => 1
I am using this query with the 'chartkick' gem that groups them in a graph by area, where when passing the mouse in each area it shows me this
Marketing
Open:5
Close:1
Attended:2
In process:4
Monitoring
Open:2
Close:7
Attended:3
In process:4
I would like to add to that information the total amount and what is displayed like this
Marketing
Open:5
Close:1
Attended:2
In process:4
Total:12
Monitoring
Open:2
Close:7
Attended:3
In process:4
Total:16
I was looking for the solution but I don't know how to achieve this
CodePudding user response:
Given your current output as h
h = {[ "Open", "BROWSER" ] => 2,[ "Open", "MARKETING" ] => 5,[ "Open", "MONITORING" ] => 2,[ "Open", "SALES" ] => 7,[ "Open", "ADMINISTRATION" ] => 8,[ "Open", "COLLECTIONS" ] => 1,[ "Open", "EMPLOYEE" ] => 8,[ "Open", "SYSTEMS" ] => 6,[ "Open", "QUALITY" ] => 4,[ "Open", "TECH SUPPORT" ] => 5,[ "Open", "STORE" ] => 2,[ "Closed", "SYSTEMS" ] => 11, [ "Closed", "MONITORING" ] => 7,[ "Closed", "ADMINISTRATION" ] => 4,[ "Closed", "QUALITY" ] => 6,[ "Closed", "STORE" ] => 6,[ "Closed", "EMPLOYEE" ] => 2,[ "Closed", "SALES" ] => 3,[ "Closed", "TECHNICAL SUPPORT" ] => 4,[ "Closed", "BROWSER" ] => 1,[ "Closed", "COLLECTIONS" ] => 2,[ "Closed", "MARKETING" ] => 1,[ "Attended", "QUALITY" ] => 3,[ "Served", "EMPLOYEE" ] => 3,[ "Served", "WAREHOUSE" ] => 5,[ "Attended", "COLLECTIONS" ] => 3,[ "Served", "SYSTEMS" ] => 8,[ "Served", "SALES" ] => 5,[ "Attended", "TECHNICAL SUPPORT" ] => 3,[ "Attended", "BROWSER" ] => 8,[ "Attended", "ADMINISTRATION" ] => 7,[ "Attended", "MONITORING" ] => 3,[ "Served", "MARKETING" ] => 2,[ "In process", "EMPLOYEE" ] => 4,[ "In process", "COLLECTIONS" ] => 2,[ "In process", "QUALITY" ] => 7,[ "In process", "MONITORING" ] => 4,[ "In process", "BROWSER" ] => 4,[ "In progress", "MARKETING" ] => 4,[ "In process", "SYSTEMS" ] => 3,[ "In process", "ADMINISTRATION" ] => 4,[ "In process", "TECHNICAL SUPPORT" ] => 3,[ "In process", "WAREHOUSE" ] => 3,[ "In process", "SALES" ] => 1}
The following will produce a Hash with the desired data structure:
h.each_with_object(Hash.new {|h,k| h[k] = {"Total"=> 0}}) do |((status,department),v),obj|
obj[department][status] = v
obj[department]["Total"] = v
end
# {"BROWSER"=>{"Total"=>15, "Open"=>2, "Closed"=>1, "Attended"=>8, "In process"=>4},
# "MARKETING"=>{"Total"=>12, "Open"=>5, "Closed"=>1, "Served"=>2, "In progress"=>4},
# "MONITORING"=>{"Total"=>16, "Open"=>2, "Closed"=>7, "Attended"=>3, "In process"=>4},
# "SALES"=>{"Total"=>16, "Open"=>7, "Closed"=>3, "Served"=>5, "In process"=>1},
# "ADMINISTRATION"=>{"Total"=>23, "Open"=>8, "Closed"=>4, "Attended"=>7, "In process"=>4},
# "COLLECTIONS"=>{"Total"=>8, "Open"=>1, "Closed"=>2, "Attended"=>3, "In process"=>2},
# "EMPLOYEE"=>{"Total"=>17, "Open"=>8, "Closed"=>2, "Served"=>3, "In process"=>4},
# "SYSTEMS"=>{"Total"=>28, "Open"=>6, "Closed"=>11, "Served"=>8, "In process"=>3},
# "QUALITY"=>{"Total"=>20, "Open"=>4, "Closed"=>6, "Attended"=>3, "In process"=>7},
# "TECH SUPPORT"=>{"Total"=>5, "Open"=>5}, "STORE"=>{"Total"=>8, "Open"=>2, "Closed"=>6},
# "TECHNICAL SUPPORT"=>{"Total"=>10, "Closed"=>4, "Attended"=>3, "In process"=>3},
# "WAREHOUSE"=>{"Total"=>8, "Served"=>5, "In process"=>3}}
CodePudding user response:
Suppose the given hash were as follows.
h = {
["Open", "BROWSER"] =>2, ["Open", "MARKETING"] =>5,
["Open", "MONITORING"] =>2, ["Closed", "MARKETING"]=>1,
["Closed", "MONITORING"] =>7, ["Attended", "BROWSER"]=>8,
["Attended", "MONITORING"]=>3, ["Closed", "BROWSER"] =>1,
["Served", "MARKETING"] =>2
}
We may compute the desired hash as follows.
h.each_with_object({}) do |((status, dept), v), g|
g.update(dept=>{ status=>v }) { |_k,o,n| o.merge(n) }
end.transform_values { |f| f.update("Total"=>f.values.sum) }
#=> { "BROWSER"=>{"Open"=>2, "Attended"=>8, "Closed"=>1, "Total"=>11},
# "MARKETING"=>{"Open"=>5, "Closed"=>1, "Served"=>2, "Total"=>8},
# "MONITORING"=>{"Open"=>2, "Closed"=>7, "Attended"=>3, "Total"=>12}}
See:
- array decomposition to better understand the way
each_with_object's block variables are written; - the form of Hash#update (a.k.a.
Hash#merge!) that takes a block (here{ |_k,o,n| o.merge(n) }) that returns the values of keys that are present in both hashes being merged._kholds the common key, which here is not used in the block calculation (as I've indicated by the underscore).oandnrespectively hold the values of the "old" and "new" values of_k.ois the value in the hash being constructed,nis the value in the hash being merged; and - Hash#transform_values.
Note the intermediate hash that is computed:
h.each_with_object({}) do |((status, dept), v), g|
g.update(dept=>{ status=>v }) { |_k,o,n| o.merge(n) }
end
#=> { "BROWSER"=>{"Open"=>2, "Attended"=>8, "Closed"=>1},
# "MARKETING"=>{"Open"=>5, "Closed"=>1, "Served"=>2},
# "MONITORING"=>{"Open"=>2, "Closed"=>7, "Attended"=>3}}
I could have computed the values of "Total" at the same time as the above was obtained (much the way @engineersmnky did), but decided to do that as a separate second step, to both simplify the calculations and facilitate testing.
