Skip to content

Instantly share code, notes, and snippets.

@abelards
Created March 7, 2022 10:53
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save abelards/3f07392ed583dbd03fce6ecb0cd935ef to your computer and use it in GitHub Desktop.
Save abelards/3f07392ed583dbd03fce6ecb0cd935ef to your computer and use it in GitHub Desktop.
# ENGLISH ABOVE, FRENCH BELOW -- VERSION FRANCAISE CI DESSOUS
# You want to tally something in Rails and you like Ruby so you've written
Object.pluck(:field).tally
# and the results look OK so you don't look further
{'ruby' => 999, 'python' => 300, 'java' => 42, 'C' => 1}
# But you're actually asking the database to do only SELECT objects.field, fetch 1342 records, and counting in Ruby
# Databases are quite cool and fast, and you'd rather do
"SELECT objects.field, COUNT(objects.field) AS objects_count FROM objects GROUP BY objects.field"
# followed by some ordering if you'd like
"ORDER BY objects_count DESC"
# Of course, don't write SQL, just write Ruby and Arel!
Object.group(:field).calculate(:count, :all)
Object.group(:field).count
# But if you ever need to add this to a more complicated request, here's how you can do:
table = Object
key = table.arel_table[:field]
request = table.reorder('objects_count DESC').select(key, key.count.as('objects_count')).group(key)
request.map{|record| [record.field, record.objects_count]}
---
# Vous avez envie de compter des Objet par le nombre d'occurrence de champ et vous aimez Ruby donc vous faites
Objet.pluck(:champ).tally
# et vous avez un résultat OK :
{'ruby' => 999, 'python' => 300, 'java' => 42, 'C' => 1}
# Sauf que ça fait SELECT objets.champ en SQL, renvoie 1342 records et fait du comptage en Ruby.
# Et les bases de données sont très fortes pour ça, laissons-leur le travail avec
"SELECT objets.champ, COUNT(objets.champ) AS count FROM objets GROUP BY objets.champ"
# et peut-être même
"ORDER BY count DESC"
# Et arel vous permet de faire ça très bien :
Objet.group(:champ).calculate(:count, :all)
Objet.group(:champ).count
# mais si vous deviez l'intégrer dans une requête bien plus complexe, voici ce que vous pouvez faire :
table = Objet
key = table.arel_table[:champ]
request = table.reorder('objects_count DESC').select(key, key.count.as('objects_count')).group(key)
request.map{|record| [record.champ, record.objects_count]}
# Voilà, je pense que pas mal de gens ont ça (et souvent même sans tally mais avec des hash et des += 1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment