在我的Rails 4应用程序中,我有一个Item模型和一个Flag模型。项目has_many
标志。标志belong_to
项目。标记具有item_id
,user_id
和reason
属性。我需要一种方法来查找未标记的随机待处理项。我正在使用enum
作为待处理状态。
我相信我可以找到一个标记为的随机待处理项目:
@pending_item = Item.pending.joins(:flags).order("RANDOM()").first
但是如何找到未标记的随机待处理项?
答案 0 :(得分:1)
使用where
与not exists
一起获取Item
s而不Flag
s:
@pending_item = Item.pending.
where("not exists (select 1 from flags where flags.item_id = items.id)").
order("RANDOM()").first
旁注:如果有许多order("RANDOM()").first
符合条件,则Item
效率不高。对于大型表格,这可能会更有效:
unflagged_pending_items = Item.pending.
where("not exists (select 1 from flags where flags.item_id = items.id)")
@pending_item = unflagged_pending_items.offset(rand unflagged_pending_items.count).first
或者,如果第一个查询不是太慢而且您每次都不需要不同的随机项,那么您可以暂时缓存结果。
答案 1 :(得分:1)
我不知道,使用子选择是否更好。我更喜欢使用ID和外键,我可以使用它。
# initialize my instance variable to have it in the view always
@pending_item = nil
# get an array with all flagged item ids
flagged_item_ids = Flag.group(:item_id).pluck(:item_id)
# search for an unflagged item, if there are item ids in the array only,
# because the statement could return a flagged item with an empty array in the condition
if flagged_item_ids > 0
@pending_item = Item.pending.where.not(id: flagged_item_ids).order("RANDOM()").first
end
@pending_item
# => an unflagged random item or nil
请记住,数组flagged_item_ids
可以容纳大量标记的项ID。这会占用大量内存。
答案 2 :(得分:0)
解决方案#1
Item.pending.joins("LEFT OUTER JOIN ( SELECT id, item_id
FROM flags
) AS temp
ON temp.item_id = items.id")
.where('temp.id = null')
.order("RANDOM()")
.first
因此,如果我们使用LEFT OUTER JOIN
,temp.id
将等于null
,如果该项目未被标记。
解决方案#2
Item.pending.where("id NOT IN ( SELECT item_id FROM flags )")
.order("RAMDOM()")
.first
很明显,我们发现一个没有标记的项目。