【问题标题】:Rails 4 ActiveRecord query for empty association on self referential has_many associationRails 4 ActiveRecord查询自引用has_many关联上的空关联
【发布时间】:2016-04-28 20:57:44
【问题描述】:

设置如下:

# app/models/booking.rb

class Booking < ActiveRecord::Base
  # Associations
  belongs_to :parent_booking, class_name: "Booking"
  has_many :child_bookings, class_name: "Booking", foreign_key: "parent_booking_id"
end

这不是必需的关系,因此并非所有预订都有 parent_booking 或 child_bookings。

尝试创建一个查询,该查询返回所有没有任何 child_bookings 的 Bookings 的 ActiveRecord::Relation,无论 parent_booking 是否存在。

以下示例(基于this SO question)适用于不同模型之间的关系的场景。但是,由于记录在同一个表中,因此它不适用于自引用关系。相反,它返回所有没有 parent_booking 的 Bookings 的 ActiveRecord::Relation。

Booking.includes(:child_bookings).where(bookings: { parent_booking_id: nil })

以下返回正确的对象,但效率极低,因为它必须为每条记录查询数据库。此外,它将它作为一个数组返回,而不是一个 ActiveRecord::Relation(更关心效率低下)。

Booking.select { |b| b.child_bookings.empty? }

我很可能忽略了一个简单的解决方案,但广泛的搜索还没有找到任何东西。谢谢!

【问题讨论】:

  • 我认为这应该可行:Booking.where({ parent_booking_id: nil })
  • @MuhammadYawarAli 返回没有父母的预订;我需要退回没有孩子的预订。

标签: ruby-on-rails ruby ruby-on-rails-4


【解决方案1】:

我会添加一个counter cache,然后查询Booking.where(child_booking_count: 0)

【讨论】:

  • 谢谢!这非常有效。标记为解决方案,因为它解决了效率问题并返回为 ActiveRecord::Relation。这也将有助于其他领域查询关联的大小。好东西。
【解决方案2】:

我认为效率低下来自急切加载。如果你只是做一个标准的左连接,我认为你会发现性能很好:

Booking.joins("LEFT JOIN bookings child_bookings ON child_bookings.parent_booking_id = bookings.id").where(child_bookings: {id: nil})

我知道您无法使用 AR 关联,但 ActiveRecord 尚未决定包含左连接。如果你想要它们,我已经做了一个要点here,你可以用它来添加它,以及考虑到这种类型的附加方法:without:然后你可以写Booking.without(:child_bookings)

【讨论】:

  • 有道理。另一个答案保留了使用 AR 关联的能力,所以我同意了,但是我可能会在 AR 关联不重要的其他场景中使用它。谢谢!
  • 当然!计数器缓存是一个很好的解决方案,并且在设置后会比这更快,因为它只需要查询一个表而无需任何连接。
【解决方案3】:

查询0条子记录的一种方法是:

parent_ids = Booking.parent_booking_ids
Booking.where('id NOT IN (?)',parent_ids)

希望它会返回所需的记录。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多