Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongoid criteria that returns nothing

I need to create a mongoid criteria which will return nothing. I couldn't find any "none"-kind of method, so I'm doing Model.where(id: nil) or Model.any_in(id: nil) instead. However this is not nice, and will also query the db.

I would like to add my own selector to mongoid that will return an empty result without even querying the db (such as Model.none()), but don't know where/how to do it. Can somebody help?

Note: I need this because the caller might chain the criteria without having to know it's already empty.

like image 805
stanley90 Avatar asked May 13 '14 14:05

stanley90


1 Answers

What version of Mongoid are you on? Because when I try Model.none it returns an empty set:

Model.none
Model.none.count # => 0

none was added in version 4. If you can’t update to that version, you could try integrating the change. These methods at at line 309 in /lib/mongoid.criteria.rb need to be defined:

def none
  @none = true and self
end

def empty_and_chainable?
  !!@none
end

Mongoid::Contextual#create_context also needs to be changed:

def create_context
  return None.new(self) if empty_and_chainable?
  embedded ? Memory.new(self) : Mongo.new(self)
end

Then you can include `/lib/mongoid/contextual/none.rb'.

EDIT: this Gist backports .none to Mongoid 3:

module Mongoid
  class Criteria
    def none
      @none = true and self
    end

    def empty_and_chainable?
      !!@none
    end
  end

  module Contextual  
    class None
      include ::Enumerable

      # Previously included Queryable, which has been extracted in v4
      attr_reader :collection, :criteria, :klass

      def blank?
        !exists?
      end
      alias :empty? :blank?

      attr_reader :criteria, :klass

      def ==(other)
        other.is_a?(None)
      end

      def each
        if block_given?
          [].each { |doc| yield(doc) }
          self
        else
          to_enum
        end
      end

      def exists?; false; end

      def initialize(criteria)
        @criteria, @klass = criteria, criteria.klass
      end

      def last; nil; end

      def length
        entries.length
      end
      alias :size :length
    end

    private

    def create_context
      return None.new(self) if empty_and_chainable?
      embedded ? Memory.new(self) : Mongo.new(self)
    end  
  end

  module Finders
    delegate :none, to: :with_default_scope
  end
end
like image 99
Buck Doyle Avatar answered Nov 02 '22 00:11

Buck Doyle