Reputation: 97
I am making a simple query in rails using the join method but I am getting duplicated values. I want to understand the way this works and why I get the duplicates.
as an example: I have 10 users is the db with 2 pets each
Users.joins(:pets).size # => 20
This returns 2 of each user
Upvotes: 1
Views: 1538
Reputation: 29820
This is how sql INNER JOIN
behaves.
SELECT "users".* FROM "users" INNER JOIN "pets" ON "pets"."user_id" = "users"."id"
Pet
has the user_id
column, so for every pet that has a user a result is added.
We can see this database result (with user.id and pet.id selected)
>> ActiveRecord::Base.connection.execute(User.select("users.id as user, pets.id as pet").joins(:pets).to_sql).to_a
(0.9ms) SELECT users.id as user, pets.id as pet FROM "users" INNER JOIN "pets" ON "pets"."user_id" = "users"."id"
=> [
{"user"=>1, "pet"=>1},
{"user"=>1, "pet"=>2}
]
By default rails just doesn't select any values from joined tables, it only does SELECT "users".*
to give you a valid User
object at the end.
>> ActiveRecord::Base.connection.execute(User.joins(:pets).to_sql).to_a
(0.9ms) SELECT "users".* FROM "users" INNER JOIN "pets" ON "pets"."user_id" = "users"."id"
=> [
{"id"=>1, "name"=>"User 1"},
{"id"=>1, "name"=>"User 1"}
]
So, you only see duplicated results.
If you're trying to filter users who have pets use distinct
>> User.joins(:pets).distinct
User Load (1.5ms) SELECT DISTINCT "users".* FROM "users" INNER JOIN "pets" ON "pets"."user_id" = "users"."id"
=> [
#<User:0x00007f2c9ea235d8 id: 1, name: "User 1">
]
It you're trying to preload pets, use includes
>> User.includes(:pets)
User Load (0.8ms) SELECT "users".* FROM "users"
Pet Load (0.6ms) SELECT "pets".* FROM "pets" WHERE "pets"."user_id" IN ($1, $2) [["user_id", 1], ["user_id", 2]]
=> [
#<User:0x00007f2c9e6325f0 id: 1, name: "User 1">,
#<User:0x00007f2c9e6324d8 id: 2, name: "User 2"> # <= user without pets
]
For more details see 'Related' questions =>
and my other answer from yesterday https://stackoverflow.com/a/72005685/207090
Upvotes: 1