Ruby on rails Rails-获取父id不在任何子关联中的对象
我有这两种型号:Ruby on rails Rails-获取父id不在任何子关联中的对象,ruby-on-rails,join,Ruby On Rails,Join,我有这两种型号: Collabs - id - title # has_many :collaborations Collaborations - collab_id - user_id - status # belongs_to :collab # belong_to :user 在查询中,我不想获取所有协作,因为子协作关联中不存在某个用户id。一个协作可以有零到多个协作,并且协作将具有不同的用户id 我尝试过使用作用域: collabs = Collab.available_for_us
Collabs
- id
- title
# has_many :collaborations
Collaborations
- collab_id
- user_id
- status
# belongs_to :collab
# belong_to :user
在查询中,我不想获取所有协作,因为子协作关联中不存在某个用户id。一个协作可以有零到多个协作,并且协作将具有不同的用户id
我尝试过使用作用域:
collabs = Collab.available_for_user(2)
scope :available_for_user, -> (user_id) { joins(:collaborations).where.not(collaborations: {user_id: user_id}) }
我还尝试:
scope :available_for_user, -> (user_id) { left_outer_joins(:collaborations).where.not(collaborations: {user_id: user_id}) }
这是在控制台中输出的SQL:
SELECT "collabs".* FROM "collabs" LEFT OUTER JOIN "collaborations" ON "collaborations"."collab_id" = "collabs"."id" WHERE ("collaborations"."user_id" != $1) [["user_id", 13]]
如果子关联仅具有提供的用户id,但如果协作具有另一个与另一个用户id的协作,则可以使用上述作用域获取此协作。这是您的调用:
Collab.find_by_sql [
"SELECT *
FROM collabs
WHERE id NOT IN (
SELECT C.id
FROM collabs C
JOIN collaborations CL ON CL.collab_id = C.id
WHERE CL.user_id = :user_id)",
{ user_id: user_id }
]
说明:要获取所选用户id中没有协作的协作,必须找到具有该协作的协作,并将其排除在外:
如果没有SQL,使用纯Ruby,它可以写成:
Collab.where.not(
id: Collab.joins(:collaborations)
.where(collaborations: { user_id: user_id })
.pluck(:id)
)
或者,更详细地说:
# Inner query to find collabs with collaborations for given user_id:
# SELECT C.id
# FROM collabs C
# JOIN collaborations CL ON CL.collab_id = C.id
# WHERE CL.user_id = :user_id
ids = Collab.joins(:collaborations)
.where(collaborations: { user_id: user_id })
.pluck(:id)
# Final query:
# SELECT *
# FROM collabs
# WHERE id NOT IN :ids
Collab.where.not(id: ids)
它生成两个SQL调用,而不是第一种情况下的一个SQL调用,因此为了性能起见,请避免这样做。您可以轻松地使用where.not代替where
另一个选项是按collab_id对协作进行分组,然后使用聚合函数映射每个协作的所有用户id并进行检查:
scope :available_for_user, -> (user_id) {
joins(<<~CUSTOM_SQL_JOIN
INNER JOIN (
SELECT collab_id, array_agg(user_id) as user_ids FROM collaborations GROUP BY collab_id
) collaborations_by_collab ON #{user_id} IN collaborations_by_collab.user_ids
CUSTOM_SQL_JOIN
)
}
Ref:这是MySQL、postgresql、…@codenamev吗?我正在使用postgresOkay,但为什么最后一个调用了两次,而第一个调用了一次?第一次调用-查找具有给定用户id的协作的协作id。第二次调用-排除它们。效果很好,谢谢。我还想知道如何在普通ruby中进行相同的调用,而不进行两次调用,如果有办法的话是的,这很有意义!对不起,这是我的问题,只是打错了。编辑它
scope :available_for_user, -> (user_id) {
joins(<<~CUSTOM_SQL_JOIN
INNER JOIN (
SELECT collab_id, array_agg(user_id) as user_ids FROM collaborations GROUP BY collab_id
) collaborations_by_collab ON #{user_id} IN collaborations_by_collab.user_ids
CUSTOM_SQL_JOIN
)
}