'Check if record does NOT exist in Rails (from array of ids)?

I can do this to check if a record(s) exists (say id "1" exists, but "2" and "3" don't):

Model.exists?(:id => [1, 2, 3]) #=> true

How do I do the opposite, so:

Model.not_exists?(:id => [1, 2, 3]) #=> true


Solution 1:[1]

If you only need search records through ID you can try this

class Model
  def self.not_exists?(ids)
    self.find(ids)
    false
  rescue
    true
  end
end

If any of the IDs does not exist the find method will raise a ActiveRecord::RecordNotFound exception that we simply catch and return true.

Excuse my English :)

Solution 2:[2]

just add a ! operator

!Model.exists?(:id => [1, 2, 3]) #=> true

Solution 3:[3]

Use empty?, this is what you want. It uses count(*) vs select 1 as one.

> Rocketeer.where(:id => [1, 2, 3]).empty?
   (0.6ms)  SELECT COUNT(*) FROM "rocketeers" WHERE "rocketeers"."id" IN (1, 2, 3)
=> false

> Rocketeer.where(:id => [1, 2, 3]).any?
   (0.5ms)  SELECT COUNT(*) FROM "rocketeers" WHERE "rocketeers"."id" IN (1, 2, 3)
=> true

> Rocketeer.where(:id => [1, 2, 3]).exists?
  Rocketeer Exists (0.5ms)  SELECT  1 AS one FROM "rocketeers" WHERE "rocketeers"."id" IN (1, 2, 3) LIMIT 1
=> true

Solution 4:[4]

class Model
  def self.does_not_exist?(ids)
    Model.where(id: ids).count < ids.size
  end
end

Explanation: If (and only if) all the instances you're looking for exist, Model.where(id: ids).count is equal to ids.size.

However if there are one or more instances missing, the count will be lower, meaning that there's a record that does not exist.

Solution 5:[5]

A more Ruby-esque way of doing it would be to use unless with exists?. This way, you don't have to use !. I imagine your use case is something like this:

def my_method
    return unless Model.exists?(:id => [1, 2, 3])

    # do something
end

You can replace 1, 2, 3 with a variable (call it id or something) and even remove the array altogether if you'd like: .exists?(id: id)

Solution 6:[6]

Another simple way is to use the where method with an array of id's.

# If the count of the query is equal to the count of all of the id's then the statement will return false.
# Else it will return true if not all ids exists in the database.
Model.where(id: [1, 2, 3]).count < [1,2,3].count

Solution 7:[7]

To ensure all ids exist, not just one the following works without have to rescue

ids = [1,2,3]
Model.where(id: ids).count != ids.length

The exists? method will return true if any of the ids match. The above will ensure all ids exist.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 afgomez
Solution 2 GSto
Solution 3
Solution 4
Solution 5 Sticky
Solution 6
Solution 7 surgentt