Class Mongo::Cursor
In: lib/mongo/cursor.rb
Parent: Object

A cursor over query results. Returned objects are hashes.

Methods

add_option   alive?   batch_size   close   closed?   count   each   explain   has_next?   inspect   limit   new   next   next_document   query_options_hash   query_opts   remove_option   rewind!   skip   sort   to_a  

Included Modules

Enumerable Mongo::Constants Mongo::Conversions Mongo::Logging

Attributes

collection  [R] 
cursor_id  [R] 
fields  [R] 
full_collection_name  [R] 
hint  [R] 
options  [R] 
order  [R] 
selector  [R] 
show_disk_loc  [R] 
snapshot  [R] 
timeout  [R] 
transformer  [R] 

Public Class methods

Create a new cursor.

Note: cursors are created when executing queries using [Collection#find] and other similar methods. Application developers shouldn‘t have to create cursors manually.

@return [Cursor]

@core cursors constructor_details

[Source]

# File lib/mongo/cursor.rb, line 39
    def initialize(collection, opts={})
      @cursor_id  = nil

      @db         = collection.db
      @collection = collection
      @connection = @db.connection
      @logger     = @connection.logger

      # Query selector
      @selector   = opts[:selector] || {}

      # Special operators that form part of $query
      @order      = opts[:order]
      @explain    = opts[:explain]
      @hint       = opts[:hint]
      @snapshot   = opts[:snapshot]
      @max_scan   = opts.fetch(:max_scan, nil)
      @return_key = opts.fetch(:return_key, nil)
      @show_disk_loc = opts.fetch(:show_disk_loc, nil)

      # Wire-protocol settings
      @fields     = convert_fields_for_query(opts[:fields])
      @skip       = opts[:skip]     || 0
      @limit      = opts[:limit]    || 0
      @tailable   = opts[:tailable] || false
      @timeout    = opts.fetch(:timeout, true)
      @options    = 0

      # Use this socket for the query
      @socket     = opts[:socket]

      @closed       = false
      @query_run    = false

      @transformer = opts[:transformer]
      if value = opts[:read]
        Mongo::Support.validate_read_preference(value)
      else
        value = collection.read_preference
      end
      @read_preference = value.is_a?(Hash) ? value.dup : value
      batch_size(opts[:batch_size] || 0)

      @full_collection_name = "#{@collection.db.name}.#{@collection.name}"
      @cache        = []
      @returned     = 0

      if(!@timeout)
        add_option(OP_QUERY_NO_CURSOR_TIMEOUT)
      end
      if(@read_preference != :primary)
        add_option(OP_QUERY_SLAVE_OK)
      end
      if(@tailable)
        add_option(OP_QUERY_TAILABLE)
      end

      if @collection.name =~ /^\$cmd/ || @collection.name =~ /^system/
        @command = true
      else
        @command = false
      end

      @checkin_read_pool = false
      @checkin_connection = false
      @read_pool = nil
    end

Public Instance methods

Add an option to the query options bitfield.

@param opt a valid query option

@raise InvalidOperation if this method is run after the cursor has bee

  iterated for the first time.

@return [Integer] the current value of the options bitfield for this cursor.

@see www.mongodb.org/display/DOCS/Mongo+Wire+Protocol#MongoWireProtocol-Mongo::Constants::OPQUERY

[Source]

# File lib/mongo/cursor.rb, line 377
    def add_option(opt)
      check_modifiable

      @options |= opt
      @options
    end

Guess whether the cursor is alive on the server.

Note that this method only checks whether we have a cursor id. The cursor may still have timed out on the server. This will be indicated in the next call to Cursor#next.

@return [Boolean]

[Source]

# File lib/mongo/cursor.rb, line 115
    def alive?
      @cursor_id && @cursor_id != 0
    end

Set the batch size for server responses.

Note that the batch size will take effect only on queries where the number to be returned is greater than 100.

This can not override MongoDB‘s limit on the amount of data it will return to the client. Depending on server version this can be 4-16mb.

@param [Integer] size either 0 or some integer greater than 1. If 0,

  the server will determine the batch size.

@return [Cursor]

[Source]

# File lib/mongo/cursor.rb, line 267
    def batch_size(size=nil)
      return @batch_size unless size
      check_modifiable
      if size < 0 || size == 1
        raise ArgumentError, "Invalid value for batch_size #{size}; must be 0 or > 1."
      else
        @batch_size = @limit != 0 && size > @limit ? @limit : size
      end

      self
    end

Close the cursor.

Note: if a cursor is read until exhausted (read until Mongo::Constants::OP_QUERY or Mongo::Constants::OP_GETMORE returns zero for the cursor id), there is no need to close it manually.

Note also: Collection#find takes an optional block argument which can be used to ensure that your cursors get closed.

@return [True]

[Source]

# File lib/mongo/cursor.rb, line 336
    def close
      if @cursor_id && @cursor_id != 0
        message = BSON::ByteBuffer.new([0, 0, 0, 0])
        message.put_int(1)
        message.put_long(@cursor_id)
        log(:debug, "Cursor#close #{@cursor_id}")
        @connection.send_message(Mongo::Constants::OP_KILL_CURSORS, message, :connection => :reader)
      end
      @cursor_id = 0
      @closed    = true
    end

Is this cursor closed?

@return [Boolean]

[Source]

# File lib/mongo/cursor.rb, line 351
    def closed?
      @closed
    end

Get the size of the result set for this query.

@param [Boolean] whether of not to take notice of skip and limit

@return [Integer] the number of objects in the result set for this query.

@raise [OperationFailure] on a database error.

[Source]

# File lib/mongo/cursor.rb, line 181
    def count(skip_and_limit = false)
      command = BSON::OrderedHash["count",  @collection.name, "query",  @selector]

      if skip_and_limit
        command.merge!(BSON::OrderedHash["limit", @limit]) if @limit != 0
        command.merge!(BSON::OrderedHash["skip", @skip]) if @skip != 0
      end

      command.merge!(BSON::OrderedHash["fields", @fields])

      response = @db.command(command)
      return response['n'].to_i if Mongo::Support.ok?(response)
      return 0 if response['errmsg'] == "ns missing"
      raise OperationFailure.new("Count failed: #{response['errmsg']}", response['code'], response)
    end

Iterate over each document in this cursor, yielding it to the given block.

Iterating over an entire cursor will close it.

@yield passes each document to a block for processing.

@example if ‘comments’ represents a collection of comments:

  comments.find.each do |doc|
    puts doc['user']
  end

[Source]

# File lib/mongo/cursor.rb, line 290
    def each
      while doc = self.next
        yield doc
      end
    end

Get the explain plan for this cursor.

@return [Hash] a document containing the explain plan for this cursor.

@core explain explain-instance_method

[Source]

# File lib/mongo/cursor.rb, line 317
    def explain
      c = Cursor.new(@collection,
        query_options_hash.merge(:limit => -@limit.abs, :explain => true))
      explanation = c.next_document
      c.close

      explanation
    end

Determine whether this cursor has any remaining results.

@return [Boolean]

[Source]

# File lib/mongo/cursor.rb, line 170
    def has_next?
      num_remaining > 0
    end

Clean output for inspect.

[Source]

# File lib/mongo/cursor.rb, line 419
    def inspect
      "<Mongo::Cursor:0x#{object_id.to_s(16)} namespace='#{@db.name}.#{@collection.name}' " +
        "@selector=#{@selector.inspect} @cursor_id=#{@cursor_id}>"
    end

Limit the number of results to be returned by this cursor.

This method overrides any limit specified in the Collection#find method, and only the last limit applied has an effect.

@return [Integer] the current number_to_return if no parameter is given.

@raise [InvalidOperation] if this cursor has already been used.

@core limit limit-instance_method

[Source]

# File lib/mongo/cursor.rb, line 230
    def limit(number_to_return=nil)
      return @limit unless number_to_return
      check_modifiable

      @limit = number_to_return
      self
    end

Get the next document specified the cursor options.

@return [Hash, Nil] the next document or Nil if no documents remain.

[Source]

# File lib/mongo/cursor.rb, line 122
    def next
      if @cache.length == 0
        if @query_run && (@options & OP_QUERY_EXHAUST != 0)
          close
          return nil
        else
          refresh
        end
      end
      doc = @cache.shift

      if doc && doc['$err']
        err = doc['$err']

        # If the server has stopped being the master (e.g., it's one of a
        # pair but it has died or something like that) then we close that
        # connection. The next request will re-open on master server.
        if err.include?("not master")
          @connection.close
          raise ConnectionFailure.new(err, doc['code'], doc)
        end

        raise OperationFailure.new(err, doc['code'], doc)
      end

      if @transformer.nil?
        doc
      else
        @transformer.call(doc) if doc
      end
    end
next_document()

Alias for next

Get the query options for this Cursor.

@return [Hash]

[Source]

# File lib/mongo/cursor.rb, line 404
    def query_options_hash
      { :selector => @selector,
        :fields   => @fields,
        :skip     => @skip,
        :limit    => @limit,
        :order    => @order,
        :hint     => @hint,
        :snapshot => @snapshot,
        :timeout  => @timeout,
        :max_scan => @max_scan,
        :return_key => @return_key,
        :show_disk_loc => @show_disk_loc }
    end

Returns an integer indicating which query options have been selected.

@return [Integer]

@see www.mongodb.org/display/DOCS/Mongo+Wire+Protocol#MongoWireProtocol-Mongo::Constants::OPQUERY The MongoDB wire protocol.

[Source]

# File lib/mongo/cursor.rb, line 361
    def query_opts
      warn "The method Cursor#query_opts has been deprecated " +
        "and will removed in v2.0. Use Cursor#options instead."
      @options
    end

Remove an option from the query options bitfield.

@param opt a valid query option

@raise InvalidOperation if this method is run after the cursor has bee

  iterated for the first time.

@return [Integer] the current value of the options bitfield for this cursor.

@see www.mongodb.org/display/DOCS/Mongo+Wire+Protocol#MongoWireProtocol-Mongo::Constants::OPQUERY

[Source]

# File lib/mongo/cursor.rb, line 394
    def remove_option(opt)
      check_modifiable

      @options &= ~opt
      @options
    end

Reset this cursor on the server. Cursor options, such as the query string and the values for skip and limit, are preserved.

[Source]

# File lib/mongo/cursor.rb, line 157
    def rewind!
      close
      @cache.clear
      @cursor_id  = nil
      @closed     = false
      @query_run  = false
      @n_received = nil
      true
    end

Skips the first number_to_skip results of this cursor. Returns the current number_to_skip if no parameter is given.

This method overrides any skip specified in the Collection#find method, and only the last skip applied has an effect.

@return [Integer]

@raise [InvalidOperation] if this cursor has already been used.

[Source]

# File lib/mongo/cursor.rb, line 247
    def skip(number_to_skip=nil)
      return @skip unless number_to_skip
      check_modifiable

      @skip = number_to_skip
      self
    end

Sort this cursor‘s results.

This method overrides any sort order specified in the Collection#find method, and only the last sort applied has an effect.

@param [Symbol, Array] key_or_list either 1) a key to sort by 2)

  an array of [key, direction] pairs to sort by or 3) a hash of
  field => direction pairs to sort by. Direction should be specified as
  Mongo::ASCENDING (or :ascending / :asc) or Mongo::DESCENDING
  (or :descending / :desc)

@raise [InvalidOperation] if this cursor has already been used.

@raise [InvalidSortValueError] if the specified order is invalid.

[Source]

# File lib/mongo/cursor.rb, line 211
    def sort(order, direction=nil)
      check_modifiable

      order = [[order, direction]] unless direction.nil?

      @order = order
      self
    end

Receive all the documents from this cursor as an array of hashes.

Notes:

If you‘ve already started iterating over the cursor, the array returned by this method contains only the remaining documents. See Cursor#rewind! if you need to reset the cursor.

Use of this method is discouraged - in most cases, it‘s much more efficient to retrieve documents as you need them by iterating over the cursor.

@return [Array] an array of documents.

[Source]

# File lib/mongo/cursor.rb, line 308
    def to_a
      super
    end

[Validate]