John Smith
John Smith

Reputation: 1886

ruby group by hashes' values in hash

sorry about the title, cannot express myself better.

I have this:

{
  7758 => { 3259 => 10, 39625 => 10, 36410 => 20, 36238 => 20, 34951 => 20, 32101 => 10},
  7916 => { 3259 => 10, 39625 => 10, 36410 => 20, 36238 => 20, 34951 => 20, 32101 => 10},
  8857 => { 1000 => 10, 39625 => 10 }
}

the keys of those hashes represents record ids, the values represent the data that should go in their row attribute.

problem is that this hash can weigh a lot, so it's imprudent to issue an update on the database for each record represented in the hash.

instead I thought about grouping up hashes with identical values and have a structure for which I can just issue an update to records in one shot.

comparing hashes values can be done even by transforming the nested hashes themselves into a json string, since it's the datatype we use for that column.

in the end I'd like to issue an update_all for a series of variants that has the same hash content, I understand that the number of updates issues to the database is 1:1 to how unique are the hash values, but I kinda have the choice to sort their keys in someway before the comparison should we have something smart to compare existing values rather than converting the content to a string for comparison purposes.

what happens now is a normal update on each hash record in a cycle:

UPDATE "table" SET "rates" = '{"3259":10,"39625":10,"36410":20,"36238":20,"34951":20,"32101":10}', WHERE "table"."variant_id" = 7758
UPDATE "table" SET "rates" = '{"3259":10,"39625":10,"36410":20,"36238":20,"34951":20,"32101":10}', WHERE "table"."variant_id" = 7916
UPDATE "table" SET "rates" = '{"1000":10,"39625":10}' WHERE "table"."variant_id" = 7916

I'd like to transform the original structure in something that allows me to perform this:

UPDATE "table" SET "rates" = '{"3259":10,"39625":10,"36410":20,"36238":20,"34951":20,"32101":10}', WHERE "table"."variant_id" IN(7758, 7916)
UPDATE "table" SET "rates" = '{"1000":10,"39625":10}' WHERE "table"."variant_id" = 7916

I tried a

hash.group_by { |h| h[1].to_json }.each do |rate|

but I have this in rate:

["{\"3259\":10,\"39625\":10,\"36410\":20,\"36238\":20,\"34951\":20,\"32101\
":10}", [[7758, {3259=>10, 39625=>10, 36410=>20, 36238=>20, 34951=>20,
 32101=>10}], [7916, {3259=>10, 39625=>10, 36410=>20, 36238=>20, 
34951=>20, 32101=>10}], [8857, {3259=>10, 39625=>1...

Upvotes: 1

Views: 496

Answers (1)

Brian Underwood
Brian Underwood

Reputation: 10856

Maybe something like this:

result = hash.each_with_object({}) do |(id, attributes), result|
  json_string = attributes.to_json
  result[json_string] ||= []
  result[json_string] << id
end

result.each do |json_string, ids|
  # ...
end

Upvotes: 1

Related Questions