From 330f339fa6864713db4d4436ef3d1c2dc308f457 Mon Sep 17 00:00:00 2001 From: jbranchaud Date: Sun, 26 Dec 2021 17:40:47 -0600 Subject: [PATCH] Add Find Records With Multiple Associated Records as a Rails til --- README.md | 3 +- ...ecords-with-multiple-associated-records.md | 37 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 rails/find-records-with-multiple-associated-records.md diff --git a/README.md b/README.md index e41477e..c0e0e90 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ pairing with smart people at Hashrocket. For a steady stream of TILs, [sign up for my newsletter](https://crafty-builder-6996.ck.page/e169c61186). -_1173 TILs and counting..._ +_1174 TILs and counting..._ --- @@ -705,6 +705,7 @@ _1173 TILs and counting..._ - [Disambiguate Where In A Joined Relation](rails/disambiguate-where-in-a-joined-relation.md) - [Ensure Migrations Use The Latest Schema](rails/ensure-migrations-use-the-latest-schema.md) - [Find Or Create A Record With FactoryBot](rails/find-or-create-a-record-with-factory-bot.md) +- [Find Records With Multiple Associated Records](rails/find-records-with-multiple-associated-records.md) - [Force All Users To Sign Out](rails/force-all-users-to-sign-out.md) - [Generating And Executing SQL](rails/generating-and-executing-sql.md) - [Get An Array Of Values From The Database](rails/get-an-array-of-values-from-the-database.md) diff --git a/rails/find-records-with-multiple-associated-records.md b/rails/find-records-with-multiple-associated-records.md new file mode 100644 index 0000000..b4a57e6 --- /dev/null +++ b/rails/find-records-with-multiple-associated-records.md @@ -0,0 +1,37 @@ +# Find Records With Multiple Associated Records + +Relational data often involves a table that has a one-to-many relationship with +another table. For instance, a team can be made up of many members. A question +we may want to ask of that data is, what are the records (`teams`) that are +associated with more than one of this other table (`members`). + +With a few SQL features that are supported by ActiveRecord's query syntax, we +can answer that question. + +To make it interesting, let's say we are trying to answer the question, "what +are the teams that have multiple _active_ members?" + +```ruby +Team + .joins(:members) + .where(members: { status: 'active' }) + .having("count(*) >= 2") + .group("teams.id") + .count + +=> { + 123 => 2, + 345 => 3, + 567 => 2, + ... +} +``` + +That final `.count` is going to manifest as a `count(*)` in the `select` +clause. That `count(*)` aggregate combined with the `group("teams.id")` is +going to flatten the results to be unique by team ID. Then the `having` clause +will filter out all teams with a member count less than 2. And before that, the +where will cut down the members to only those that are `active`. + +If you just want the IDs, you can tack a `#keys` call onto the end of that +query result.