Class: Mongo::Cursor

Inherits:
Object show all
Includes:
Enumerable, Conversions
Defined in:
lib/mongo/cursor.rb

Overview

A cursor over query results. Returned objects are hashes.

Constant Summary

Constants included from Conversions

Mongo::Conversions::ASCENDING_CONVERSION, Mongo::Conversions::DESCENDING_CONVERSION

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Conversions

#array_as_sort_parameters, #formatted_sort_clause, #sort_value, #string_as_sort_parameters

Constructor Details

#initialize(collection, options = {}) ⇒ Cursor

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.



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/mongo/cursor.rb', line 32

def initialize(collection, options={})
  @db         = collection.db
  @collection = collection
  @connection = @db.connection

  @selector   = convert_selector_for_query(options[:selector])
  @fields     = convert_fields_for_query(options[:fields])
  @admin      = options[:admin]    || false
  @skip       = options[:skip]     || 0
  @limit      = options[:limit]    || 0
  @order      = options[:order]
  @hint       = options[:hint]
  @snapshot   = options[:snapshot]
  @timeout    = options[:timeout]  || false
  @explain    = options[:explain]
  @socket     = options[:socket]

  @full_collection_name = "#{@collection.db.name}.#{@collection.name}"
  @cache = []
  @closed = false
  @query_run = false
end

Instance Attribute Details

#adminObject (readonly)

Returns the value of attribute admin.



22
23
24
# File 'lib/mongo/cursor.rb', line 22

def admin
  @admin
end

#collectionObject (readonly)

Returns the value of attribute collection.



22
23
24
# File 'lib/mongo/cursor.rb', line 22

def collection
  @collection
end

#fieldsObject (readonly)

Returns the value of attribute fields.



22
23
24
# File 'lib/mongo/cursor.rb', line 22

def fields
  @fields
end

#full_collection_nameObject (readonly)

Returns the value of attribute full_collection_name.



22
23
24
# File 'lib/mongo/cursor.rb', line 22

def full_collection_name
  @full_collection_name
end

#hintObject (readonly)

Returns the value of attribute hint.



22
23
24
# File 'lib/mongo/cursor.rb', line 22

def hint
  @hint
end

#orderObject (readonly)

Returns the value of attribute order.



22
23
24
# File 'lib/mongo/cursor.rb', line 22

def order
  @order
end

#selectorObject (readonly)

Returns the value of attribute selector.



22
23
24
# File 'lib/mongo/cursor.rb', line 22

def selector
  @selector
end

#snapshotObject (readonly)

Returns the value of attribute snapshot.



22
23
24
# File 'lib/mongo/cursor.rb', line 22

def snapshot
  @snapshot
end

#timeoutObject (readonly)

Returns the value of attribute timeout.



22
23
24
# File 'lib/mongo/cursor.rb', line 22

def timeout
  @timeout
end

Instance Method Details

#closeTrue

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.

Returns:

  • (True)


221
222
223
224
225
226
227
228
229
230
# File 'lib/mongo/cursor.rb', line 221

def close
  if @cursor_id
    message = ByteBuffer.new([0, 0, 0, 0])
    message.put_int(1)
    message.put_long(@cursor_id)
    @connection.send_message(Mongo::Constants::OP_KILL_CURSORS, message, "cursor.close()")
  end
  @cursor_id = 0
  @closed    = true
end

#closed?Boolean

Is this cursor closed?

Returns:

  • (Boolean)


235
# File 'lib/mongo/cursor.rb', line 235

def closed?; @closed; end

#countInteger

Get the size of the result set for this query.

Returns:

  • (Integer)

    the number of objects in the result set for this query. Does not take limit and skip into account.

Raises:



91
92
93
94
95
96
97
98
99
# File 'lib/mongo/cursor.rb', line 91

def count
  command = OrderedHash["count",  @collection.name,
                        "query",  @selector,
                        "fields", @fields]
  response = @db.command(command)
  return response['n'].to_i if response['ok'] == 1
  return 0 if response['errmsg'] == "ns missing"
  raise OperationFailure, "Count failed: #{response['errmsg']}"
end

#each { ... } ⇒ Object

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

Iterating over an entire cursor will close it.

Examples:

if ‘comments’ represents a collection of comments:

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

Yields:

  • passes each document to a block for processing.



172
173
174
175
176
177
178
# File 'lib/mongo/cursor.rb', line 172

def each
  num_returned = 0
  while more? && (@limit <= 0 || num_returned < @limit)
    yield next_document
    num_returned += 1
  end
end

#explainHash

Get the explain plan for this cursor.

Returns:

  • (Hash)

    a document containing the explain plan for this cursor.



203
204
205
206
207
208
209
# File 'lib/mongo/cursor.rb', line 203

def explain
  c = Cursor.new(@collection, query_options_hash.merge(:limit => -@limit.abs, :explain => true))
  explanation = c.next_document
  c.close

  explanation
end

#limit(number_to_return = nil) ⇒ Integer

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.

Returns:

  • (Integer)

    the current number_to_return if no parameter is given.

Raises:



134
135
136
137
138
139
140
141
# File 'lib/mongo/cursor.rb', line 134

def limit(number_to_return=nil)
  return @limit unless number_to_return
  check_modifiable
  raise ArgumentError, "limit requires an integer" unless number_to_return.is_a? Integer

  @limit = number_to_return
  self
end

#next_documentHash, Nil

Get the next document specified the cursor options.

Returns:

  • (Hash, Nil)

    the next document or Nil if no documents remain.



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/mongo/cursor.rb', line 58

def next_document
  refill_via_get_more if num_remaining == 0
  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 == "not master"
      raise ConnectionFailure, err
      @connection.close
    end

    raise OperationFailure, err
  end

  doc
end

#next_objectObject

Deprecated.

use Cursor#next_document instead.



80
81
82
83
# File 'lib/mongo/cursor.rb', line 80

def next_object
  warn "Cursor#next_object is deprecated; please use Cursor#next_document instead."
  next_document
end

#query_options_hashHash

Get the query options for this Cursor.

Returns:

  • (Hash)


252
253
254
255
256
257
258
259
260
261
262
# File 'lib/mongo/cursor.rb', line 252

def query_options_hash
  { :selector => @selector,
    :fields   => @fields,
    :admin    => @admin,
    :skip     => @skip_num,
    :limit    => @limit_num,
    :order    => @order,
    :hint     => @hint,
    :snapshot => @snapshot,
    :timeout  => @timeout }
end

#query_optsInteger

Returns an integer indicating which query options have been selected.

The MongoDB wire protocol.



243
244
245
246
247
# File 'lib/mongo/cursor.rb', line 243

def query_opts
  timeout  = @timeout ? 0 : Mongo::Constants::OP_QUERY_NO_CURSOR_TIMEOUT
  slave_ok = @connection.slave_ok? ? Mongo::Constants::OP_QUERY_SLAVE_OK : 0
  slave_ok + timeout
end

#skip(number_to_skip = nil) ⇒ Integer

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.

Returns:

  • (Integer)

Raises:



152
153
154
155
156
157
158
159
# File 'lib/mongo/cursor.rb', line 152

def skip(number_to_skip=nil)
  return @skip unless number_to_skip
  check_modifiable
  raise ArgumentError, "skip requires an integer" unless number_to_skip.is_a? Integer

  @skip = number_to_skip
  self
end

#sort(key_or_list, direction = nil) ⇒ Object

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.

Parameters:

  • key_or_list (Symbol, Array)

    either 1) a key to sort by or 2) an array of [key, direction] pairs to sort by. Direction should be specified as Mongo::ASCENDING (or :ascending / :asc) or Mongo::DESCENDING (or :descending / :desc)

Raises:



113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/mongo/cursor.rb', line 113

def sort(key_or_list, direction=nil)
  check_modifiable

  if !direction.nil?
    order = [[key_or_list, direction]]
  else
    order = key_or_list
  end

  @order = order
  self
end

#to_aArray

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

Note: 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.

Returns:

  • (Array)

    an array of documents.

Raises:

  • (InvalidOperation)

    if this cursor has already been used or if this method has already been called on the cursor.



189
190
191
192
193
194
195
196
197
198
# File 'lib/mongo/cursor.rb', line 189

def to_a
  raise InvalidOperation, "can't call Cursor#to_a on a used cursor" if @query_run
  rows = []
  num_returned = 0
  while more? && (@limit <= 0 || num_returned < @limit)
    rows << next_document
    num_returned += 1
  end
  rows
end